Main Content

Import Calls to External Code into Generated Code with Legacy Code Tool

Legacy Code Tool and Code Generation

You can use the Simulink® Legacy Code Tool to generate fully inlined C MEX S-functions for legacy or custom code. The S-functions are optimized for embedded components, such as device drivers and lookup tables, and they call existing C or C++ functions.

Note

The Legacy Code Tool can interface with C++ functions, but not C++ objects. To work around this issue so that the tool can interface with C++ objects, see Legacy Code Tool Limitations.

You can use the tool to:

  • Compile and build the generated S-function for simulation.

  • Generate a masked S-Function block that is configured to call the existing external code.

If you want to include these types of S-functions in models for which you intend to generate code, use the tool to generate a TLC block file. The TLC block file specifies how the generated code for a model calls the existing C or C++ function.

If the S-function depends on files in folders other than the folder containing the S-function dynamically loadable executable file, use the tool to generate an sFunction_makecfg.m or rtwmakecfg.m file for the S-function. Generating the file maintains those dependencies when you build a model that includes the S-function. For example, for some applications, such as custom targets, you might want to locate files in a target-specific location. The build process looks for sFunction_makecfg.m or rtwmakecfg.m in the same folder as the S-function dynamically loadable executable and calls the function in the file.

For more information, see Integrate C Functions Using Legacy Code Tool.

Generate Inlined S-Function Files for Code Generation

Depending on the code generation requirements of your application, to generate code for a model that uses the S-function, do either of the following:

  • Generate one .cpp file for the inlined S-function. In the Legacy Code Tool data structure, set the value of the Options.singleCPPMexFile field to true before generating the S-function source file from your existing C function. For example:

    def.Options.singleCPPMexFile = true;
    legacy_code('sfcn_cmex_generate', def);

  • Generate a source file and a TLC block file for the inlined S-function. For example:

    def.Options.singleCPPMexFile = false;
    legacy_code('sfcn_cmex_generate', def);
    legacy_code('sfcn_tlc_generate', def);

singleCPPMexFile Limitations

You cannot set the singleCPPMexFile field to true if

  • Options.language='C++'

  • You use one of the following Simulink objects with the IsAlias property set to true:

    • Simulink.Bus

    • Simulink.AliasType

    • Simulink.NumericType

  • The Legacy Code Tool function specification includes a void* or void** to represent scalar work data for a state argument

  • HeaderFiles field of the Legacy Code Tool structure specifies multiple header files

Apply Code Style Settings to Legacy Functions

To apply the model configuration parameters for code style to a legacy function:

  1. Initialize the Legacy Code Tool data structure. For example:

    def = legacy_code('initialize');
    
  2. In the data structure, set the value of the Options.singleCPPMexFile field to true. For example:

    def.Options.singleCPPMexFile = true;

To check the setting, enter:

def.Options.singleCPPMexFile

singleCPPMexFile Limitations

You cannot set the singleCPPMexFile field to true if

  • Options.language='C++'

  • You use one of the following Simulink objects with the IsAlias property set to true:

    • Simulink.Bus

    • Simulink.AliasType

    • Simulink.NumericType

  • The Legacy Code Tool function specification includes a void* or void** to represent scalar work data for a state argument

  • HeaderFiles field of the Legacy Code Tool structure specifies multiple header files

Address Dependencies on Files in Different Locations

By default, the Legacy Code Tool assumes that files on which an S-function depends reside in the same folder as the dynamically loadable executable file for the S-function. If your S-function depends on files that reside elsewhere and you are using the template makefile build process, generate an sFunction_makecfg.m or rtwmakecfg.m file for the S-function. For example, you might generate this file if your Legacy Code Tool data structure defines compilation resources as path names.

To generate the sFunction_makecfg.m or rtwmakecfg.m file, call the legacy_code function with 'sfcn_makecfg_generate' or 'rtwmakecfg_generate' as the first argument, and the name of the Legacy Code Tool data structure as the second argument. For example:

legacy_code('sfcn_makecfg_generate', lct_spec);

If you use multiple registration files in the same folder and generate an S-function for each file with a single call to legacy_code, the call to legacy_code that specifies 'sfcn_makecfg_generate' or 'rtwmakecfg_generate' must be common to all registration files. For more information, see Handling Multiple Registration Files.

For example, if you define defs as an array of Legacy Code Tool structures, you call legacy_code with 'sfcn_makecfg_generate' once.

defs = [defs1(:);defs2(:);defs3(:)];
legacy_code('sfcn_makecfg_generate', defs);

For more information, see Build Support for S-Functions.

Deploy S-Functions for Simulation and Code Generation

You can deploy the S-functions that you generate with the Legacy Code Tool so that other people can use them. To deploy an S-function for simulation and code generation, share the following files:

  • Registration file

  • Compiled dynamically loadable executable

  • TLC block file

  • sFunction_makecfg.m or rtwmakecfg.m file

  • Header, source, and include files on which the generated S-function depends

When you use these deployed files:

  • Before using the deployed files in a Simulink model, add the folder that contains the S-function files to the MATLAB® path.

  • If the Legacy Code Tool data structure registers required files as absolute paths and the location of the files changes, regenerate the sFunction_makecfg.m or rtwmakecfg.m file.

Integrate External C++ Objects

The Legacy Code Tool can interface with C++ functions, but not C++ objects. Using the previous example as a starting point, here is an example of how you can work around this limitation.

  • Modify the class definition for adder in a new file adder_cpp.hpp. Add three new macros that dynamically allocate a new adder object, invoke the method add_one(), and free the memory allocated. Each macro takes a pointer to an adder object. Because each function called by the Legacy Code Tool must have a C-like signature, the pointer is cached and passed as a void*. Then you must explicitly cast to adder* in the macro. The new class definition for adder:

    #ifndef _ADDER_CPP_
    #define _ADDER_CPP_
    
    class adder {
    private:
    	int int_state;
    public:
    	adder(): int_state(0) {};
    	int add_one(int increment);
    	int get_val() {return int_state;};
    };
    
    // Method wrappers implemented as macros
    #define createAdder(work1) \
        *(work1) = new adder
    
    #define deleteAdder(work1) \
        delete(static_cast<adder*>(*(work1)))
    
    #define adderOutput(work1, u1) \
        (static_cast<adder*> ((work1)))->add_one(u1)
    
    #endif /* _ADDER_CPP_ */
  • Update adder_cpp.cpp. With the class modification, instead of one global instance, each generated S-function manages its own adder object.

    #include "adder_cpp.hpp"
    
    int adder::add_one(int increment)
    {
    	int_state += increment;
        return int_state;
    }
  • Update rtwdemo_sfun_adder_cpp.cpp with the following changes:

    • StartFcnSpec calls the macro that allocates a new adder object and caches the pointer.

      def.StartFcnSpec  = 'createAdder(void **work1)';
      
    • OutputFcnSpec calls the macro that invokes the method add_one() and provides the S-function specific adder pointer object.

      def.OutputFcnSpec = 'int32 y1 = adderOutput(void *work1, int32 u1)';
    • TerminateFcnSpec calls the macro that frees the memory.

      def.TerminateFcnSpec = 'deleteAdder(void **work1)';

Legacy Code Tool Examples

Integrate External C Functions That Pass Input Arguments By Value Versus Address

This example shows how to use the Legacy Code Tool to integrate legacy C functions that pass their input arguments by value versus address.

With the Legacy Code Tool, you can:

  • Provide the legacy function specification.

  • Generate a C-MEX S-function that calls the legacy code during simulation.

  • Compile and build the generated S-function for simulation.

  • Generate a TLC block file and optional rtwmakecfg.m file that specifies how the generated code for a model calls the legacy code.

Provide the Legacy Function Specification

Legacy Code Tool functions take a specific data structure or array of structures as the argument. You can initialize the data structure by calling the function legacy_code() using 'initialize' as the first input. After initializing the structure, assign its properties to values corresponding to the legacy code being integrated. For detailed help on the properties, call legacy_code('help'). The prototypes of the legacy functions being called in this example are:

  • FLT filterV1(const FLT signal, const FLT prevSignal, const FLT gain)

  • FLT filterV2(const FLT* signal, const FLT prevSignal, const FLT gain)

FLT is a typedef to float. The legacy source code is in the files your_types.h, myfilter.h, filterV1.c, and filterV2.c.

Note the difference in the OutputFcnSpec defined in the two structures; the first case specifies that the first input argument is passed by value, while the second case specifies pass by pointer.

defs = [];

% rtwdemo_sfun_filterV1
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_filterV1';
def.OutputFcnSpec = 'single y1 = filterV1(single u1, single u2, single p1)';
def.HeaderFiles   = {'myfilter.h'};
def.SourceFiles   = {'filterV1.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};
defs = [defs; def];

% rtwdemo_sfun_filterV2
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_filterV2';
def.OutputFcnSpec = 'single y1 = filterV2(single u1[1], single u2, single p1)';
def.HeaderFiles   = {'myfilter.h'};
def.SourceFiles   = {'filterV2.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};
defs = [defs; def];

Generate S-Functions for Simulation

To generate C-MEX S-functions according to the description provided by the input argument 'defs', call the function legacy_code() again with the first input set to 'sfcn_cmex_generate'. The S-functions call the legacy functions in simulation. The source code for the S-functions is in the files rtwdemo_sfun_filterV1.c and rtwdemo_sfun_filterV2.c.

legacy_code('sfcn_cmex_generate', defs);

Compile the Generated S-Functions for Simulation

After you generate the C-MEX S-function source files, to compile the S-functions for simulation with Simulink®, call the function legacy_code() again with the first input set to 'compile'.

legacy_code('compile', defs);
### Start Compiling rtwdemo_sfun_filterV1
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex19632214', '-c', '-outdir', '/tmp/Bdoc20b_1465442_59938/tp02efb0a6_0590_4450_80d2_68d078f139ba', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/filterV1.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_filterV1.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex19632214', '/tmp/Bdoc20b_1465442_59938/tp02efb0a6_0590_4450_80d2_68d078f139ba/filterV1.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_filterV1
### Exit

### Start Compiling rtwdemo_sfun_filterV2
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex19632214', '-c', '-outdir', '/tmp/Bdoc20b_1465442_59938/tpfba35956_90bc_4567_9ac1_426335ea8221', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/filterV2.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_filterV2.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex19632214', '/tmp/Bdoc20b_1465442_59938/tpfba35956_90bc_4567_9ac1_426335ea8221/filterV2.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_filterV2
### Exit

Generate TLC Block Files for Code Generation

After you compile the S-functions and use them in simulation, you can call the function legacy_code() again with the first input set to 'sfcn_tlc_generate' to generate TLC block files. Block files specify how the generated code for a model calls the legacy code. If you do not generate TLC block files and you try to generate code for a model that includes the S-functions, code generation fails. The TLC block files for the S-functions are rtwdemo_sfun_filterV1.tlc and rtwdemo_sfun_filterV2.tlc.

legacy_code('sfcn_tlc_generate', defs);

Generate an rtwmakecfg.m File for Code Generation

After you create the TLC block files, you can call the function legacy_code() again with the first input set to 'rtwmakecfg_generate' to generate an rtwmakecfg.m file to support code generation. If the required source and header files for the S-functions are not in the same folder as the S-functions, and you want to add these dependencies in the makefile produced during code generation, generate the rtwmakecfg.m file.

legacy_code('rtwmakecfg_generate', defs);

Generate Masked S-Function Blocks for Calling the Generated S-Functions

After you compile the C-MEX S-function source, you can call the function legacy_code() again with the first input set to 'slblock_generate' to generate masked S-function blocks that call the S-functions. The software places the blocks in a new model. From there you can copy them to an existing model.

legacy_code('slblock_generate', defs);

Show the Generated Integration with Legacy Code

The model rtwdemo_lct_filter shows integration of the model with the legacy code. The subsystem TestFilter serves as a harness for the calls to the legacy C functions via the generate S-functions, with unit delays serving to store the previous output values.

open_system('rtwdemo_lct_filter')
open_system('rtwdemo_lct_filter/TestFilter')
sim('rtwdemo_lct_filter')

Integrate External C Functions That Pass the Output Argument As a Return Argument

This example shows how to use the Legacy Code Tool to integrate legacy C functions that pass their output as a return argument.

With the Legacy Code Tool, you can:

  • Provide the legacy function specification.

  • Generate a C-MEX S-function that calls the legacy code during simulation.

  • Compile and build the generated S-function for simulation.

  • Generate a TLC block file and optional rtwmakecfg.m file that specifies how the generated code for a model calls the legacy code.

Provide the Legacy Function Specification

Legacy Code Tool functions take a specific data structure or array of structures as the argument. You can initialize the data structure by calling the function legacy_code() using 'initialize' as the first input. After initializing the structure, assign its properties to values corresponding to the legacy code being integrated. For detailed help on the properties, call legacy_code('help'). The prototype of the legacy functions being called in this example is:

FLT gainScalar(const FLT in, const FLT gain)

FLT is a typedef to float. The legacy source code is in the files your_types.h, gain.h, and gainScalar.c.

% rtwdemo_sfun_gain_scalar
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_gain_scalar';
def.OutputFcnSpec = 'single y1 = gainScalar(single u1, single p1)';
def.HeaderFiles   = {'gain.h'};
def.SourceFiles   = {'gainScalar.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};

Generate an S-Function for Simulation

To generate a C-MEX S-function according to the description provided by the input argument 'def', call the function legacy_code() again with the first input set to 'sfcn_cmex_generate'. The S-function calls the legacy functions during simulation. The source code for the S-function is in the file rtwdemo_sfun_gain_scalar.c.

legacy_code('sfcn_cmex_generate', def);

Compile the Generated S-Function for Simulation

After you generate the C-MEX S-function source file, to compile the S-function for simulation with Simulink®, call the function legacy_code() again with the first input set to 'compile'.

legacy_code('compile', def);
### Start Compiling rtwdemo_sfun_gain_scalar
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex09148220', '-c', '-outdir', '/tmp/Bdoc20b_1465442_59938/tp26fab0e9_aca8_4057_9e23_e3cb99d77f01', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/gainScalar.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_gain_scalar.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex09148220', '/tmp/Bdoc20b_1465442_59938/tp26fab0e9_aca8_4057_9e23_e3cb99d77f01/gainScalar.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_gain_scalar
### Exit

Generate a TLC Block File for Code Generation

After you compile the S-function and use it in simulation, you can call the function legacy_code() again with the first input set to 'sfcn_tlc_generate' to generate a TLC block file. The block file specifies how the generated code for a model calls the legacy code. If you do not generate a TLC block file and you try to generate code for a model that includes the S-function, code generation fails. The TLC block file for the S-function is: rtwdemo_sfun_gain_scalar.tlc.

legacy_code('sfcn_tlc_generate', def);

Generate an rtwmakecfg.m File for Code Generation

After you create the TLC block file, you can call the function legacy_code() again with the first input set to 'rtwmakecfg_generate' to generate an rtwmakecfg.m file to support code generation. If the required source and header files for the S-function are not in the same folder as the S-function, and you want to add these dependencies in the makefile produced during code generation, generate the rtwmakecfg.m file.

legacy_code('rtwmakecfg_generate', def);

Generate a Masked S-Function Block for Calling the Generated S-Function

After you compile the C-MEX S-function source, you can call the function legacy_code() again with the first input set to 'slblock_generate' to generate a masked S-function block that calls that S-function. The software places the block in a new model. From there you can copy it to an existing model.

legacy_code('slblock_generate', def);

Show the Generated Integration with Legacy Code

The model rtwdemo_lct_gain shows integration of the model with the legacy code. The subsystem TestGain serves as a harness for the call to the legacy C function via the generate S-function.

open_system('rtwdemo_lct_gain')
open_system('rtwdemo_lct_gain/TestGain')
sim('rtwdemo_lct_gain')

Integrate External C++ Object Methods

Integrate legacy C++ object methods by using the Legacy Code Tool.

With the Legacy Code Tool, you can:

  • Provide the legacy function specification.

  • Generate a C++ MEX S-function that calls the legacy code during simulation.

  • Compile and build the generated S-function for simulation.

  • Generate a block TLC file and optional rtwmakecfg.m file that calls the legacy code during code generation.

Provide the Legacy Function Specification

Functions provided with the Legacy Code Tool take a specific data structure or array of structures as the argument. The data structure is initialized by calling the function legacy_code() using 'initialize' as the first input. After initializing the structure, assign its properties to values corresponding to the legacy code being integrated. For detailed help on the properties, call legacy_code('help'). The definition of the legacy C++ class in this example is:

class adder {
  private:
      int int_state;
  public:
      adder();
      int add_one(int increment);
      int get_val();
};

The legacy source code is in the files adder_cpp.h and adder_cpp.cpp.

% rtwdemo_sfun_adder_cpp
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_adder_cpp';
def.StartFcnSpec  = 'createAdder()';
def.OutputFcnSpec = 'int32 y1 = adderOutput(int32 u1)';
def.TerminateFcnSpec = 'deleteAdder()';
def.HeaderFiles   = {'adder_cpp.h'};
def.SourceFiles   = {'adder_cpp.cpp'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};
def.Options.language = 'C++';
def.Options.useTlcWithAccel = false;

Generate an S-Function for Simulation

To generate a C-MEX S-function according to the description provided by the input argument 'def', call the function legacy_code() again with the first input set to 'sfcn_cmex_generate'. The S-function calls the legacy functions during simulation. The source code for the S-function is in the file rtwdemo_sfun_adder_cpp.cpp.

legacy_code('sfcn_cmex_generate', def);

Compile the Generated S-Function for Simulation

After you generate the C-MEX S-function source file, to compile the S-function for simulation with Simulink®, call the function legacy_code() again with the first input set to 'compile'.

legacy_code('compile', def);
### Start Compiling rtwdemo_sfun_adder_cpp
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_60413/tp02da355b/ex06428671', '-c', '-outdir', '/tmp/Bdoc20b_1465442_60413/tp517bc881_295f_4182_9278_c25a3baed708', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/adder_cpp.cpp')
Building with 'g++'.
MEX completed successfully.
    mex('rtwdemo_sfun_adder_cpp.cpp', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_60413/tp02da355b/ex06428671', '-cxx', '/tmp/Bdoc20b_1465442_60413/tp517bc881_295f_4182_9278_c25a3baed708/adder_cpp.o')
Building with 'g++'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_adder_cpp
### Exit

Generate a TLC Block File for Code Generation

After you compile the S-function and use it in simulation, you can call the function legacy_code() again. Set the first input to 'sfcn_tlc_generate' to generate a TLC block file that supports code generation through Simulink® Coder™. If the TLC block file is not created and you try to generate code for a model that includes the S-function, code generation fails. The TLC block file for the S-function is: rtwdemo_sfun_adder_cpp.tlc.

legacy_code('sfcn_tlc_generate', def);

Generate an rtwmakecfg.m File for Code Generation

After you create the TLC block file, you can call the function legacy_code() again. Set the first input to 'rtwmakecfg_generate' to generate an rtwmakecfg.m file that supports code generation through Simulink® Coder™. If the required source and header files for the S-function are not in the same folder as the S-function, and you want to add these dependencies in the makefile produced during code generation, generate the rtwmakecfg.m file.

legacy_code('rtwmakecfg_generate', def);

Generate a Masked S-Function Block for Calling the Generated S-Function

After you compile the C-MEX S-function source, you can call the function legacy_code() again. Set the first input to 'slblock_generate' to generate a masked S-function block that is configured to call that S-function. The software places the block in a new model. You can copy the block to an existing model.

% legacy_code('slblock_generate', def);

Show the Generated Integration with Legacy Code

The model rtwdemo_lct_cpp shows integration with the legacy code.

open_system('rtwdemo_lct_cpp')
sim('rtwdemo_lct_cpp')

Integrate External C Functions That Pass Input and Output Arguments as Parameters with a Fixed-Point Data Type

Integrate legacy C functions that pass their inputs and outputs by using parameters of a fixed-point data type with the Legacy Code Tool.

With the Legacy Code Tool, you can:

  • Provide the legacy function specification.

  • Generate a C-MEX S-function that calls the legacy code during simulation.

  • Compile and build the generated S-function for simulation.

  • Generate a TLC block file and optional rtwmakecfg.m file that specifies how the generated code for a model calls the legacy code.

Provide the Legacy Function Specification

Legacy Code Tool functions take a specific data structure or array of structures as the argument. You can initialize the data structure by calling the function legacy_code() using 'initialize' as the first input. After initializing the structure, assign its properties to values corresponding to the legacy code being integrated. For detailed help on the properties, call legacy_code('help'). The prototype of the legacy functions being called in this example is:

myFixpt timesS16(const myFixpt in1, const myFixpt in2, const uint8_T fracLength)

myFixpt is logically a fixed point data type, which is physically a typedef to a 16-bit integer:

myFixpt = Simulink.NumericType;
myFixpt.DataTypeMode = 'Fixed-point: binary point scaling';
myFixpt.Signed = true;
myFixpt.WordLength = 16;
myFixpt.FractionLength = 10;
myFixpt.IsAlias = true;
myFixpt.HeaderFile = 'timesFixpt.h';

The legacy source code is in the files timesFixpt.h, and timesS16.c.

% rtwdemo_sfun_gain_fixpt
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_gain_fixpt';
def.OutputFcnSpec = 'myFixpt y1 = timesS16(myFixpt u1, myFixpt p1, uint8 p2)';
def.HeaderFiles   = {'timesFixpt.h'};
def.SourceFiles   = {'timesS16.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};

Generate an S-Function for Simulation

To generate a C-MEX S-function according to the description provided by the input argument 'def', call the function legacy_code() again with the first input set to 'sfcn_cmex_generate'. The S-function calls the legacy functions during simulation. The source code for the S-function is in the file rtwdemo_sfun_gain_fixpt.c.

legacy_code('sfcn_cmex_generate', def);

Compile the Generated S-Function for Simulation

After you generate the C-MEX S-function source file, to compile the S-function for simulation with Simulink®, call the function legacy_code() again with the first input set to 'compile'.

legacy_code('compile', def);
### Start Compiling rtwdemo_sfun_gain_fixpt
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex05928773', '-c', '-outdir', '/tmp/Bdoc20b_1465442_59938/tp644ad607_18ab_4194_b113_c281e4a6b524', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/timesS16.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_gain_fixpt.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex05928773', '/tmp/Bdoc20b_1465442_59938/tp644ad607_18ab_4194_b113_c281e4a6b524/timesS16.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_gain_fixpt
### Exit

Generate a TLC Block File for Code Generation

After you compile the S-function and use it in simulation, you can call the function legacy_code() again. Set the first input to 'sfcn_tlc_generate' to generate a TLC block file. The block file specifies how the generated code for a model calls the legacy code. If you do not generate a TLC block file and you try to generate code for a model that includes the S-function, code generation fails. The TLC block file for the S-function is: rtwdemo_sfun_gain_fixpt.tlc.

legacy_code('sfcn_tlc_generate', def);

Generate an rtwmakecfg.m File for Code Generation

After you create the TLC block file, you can call the function legacy_code() again. Set the first input to 'rtwmakecfg_generate' to generate an rtwmakecfg.m file that supports code generation. If the required source and header files for the S-function are not in the same folder as the S-function, and you want to add these dependencies in the makefile produced during code generation, generate the rtwmakecfg.m file.

legacy_code('rtwmakecfg_generate', def);

Generate a Masked S-Function Block for Calling the Generated S-Function

After you compile the C-MEX S-function source, you can call the function legacy_code() again. Set the first input to 'slblock_generate' to generate a masked S-function block that calls that S-function. The software places the block in a new model. You can copy the block to an existing model.

legacy_code('slblock_generate', def);

Show the Generated Integration with Legacy Code

The model rtwdemo_lct_fixpt_params shows integration of the model with the legacy code. The subsystem TestFixpt serves as a harness for the call to the legacy C function via the generated S-function.

open_system('rtwdemo_lct_fixpt_params')
open_system('rtwdemo_lct_fixpt_params/TestFixpt')
sim('rtwdemo_lct_fixpt_params')

Integrate External C Functions That Pass Input and Output Arguments as Signals with a Fixed-Point Data Type

This example shows how to use the Legacy Code Tool to integrate legacy C functions that pass their inputs and outputs by using parameters of fixed-point data type.

With the Legacy Code Tool, you can:

  • Provide the legacy function specification.

  • Generate a C-MEX S-function that calls the legacy code during simulation.

  • Compile and build the generated S-function for simulation.

  • Generate a TLC block file and optional rtwmakecfg.m file that specifies how the generated code for a model calls the legacy code.

Provide the Legacy Function Specification

Legacy Code Tool functions take a specific data structure or array of structures as the argument. You can initialize the data structure by calling the function legacy_code() using 'initialize' as the first input. After initializing the structure, assign its properties to values corresponding to the legacy code being integrated. For detailed help on the properties, call legacy_code('help'). The prototype of the legacy functions being called in this example is:

myFixpt timesS16(const myFixpt in1, const myFixpt in2, const uint8_T fracLength)

myFixpt is logically a fixed-point data type, which is physically a typedef to a 16-bit integer:

myFixpt = Simulink.NumericType;
myFixpt.DataTypeMode = 'Fixed-point: binary point scaling';
myFixpt.Signed = true;
myFixpt.WordLength = 16;
myFixpt.FractionLength = 10;
myFixpt.IsAlias = true;
myFixpt.HeaderFile = 'timesFixpt.h';

The legacy source code is in the files timesFixpt.h, and timesS16.c.

% rtwdemo_sfun_times_s16
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_times_s16';
def.OutputFcnSpec = 'myFixpt y1 = timesS16(myFixpt u1, myFixpt u2, uint8 p1)';
def.HeaderFiles   = {'timesFixpt.h'};
def.SourceFiles   = {'timesS16.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};

Generate an S-Function for Simulation

To generate a C-MEX S-function according to the description provided by the input argument 'def', call the function legacy_code() again with the first input set to 'sfcn_cmex_generate'. The S-function calls the legacy functions during simulation. The source code for the S-function is in the file rtwdemo_sfun_times_s16.c.

legacy_code('sfcn_cmex_generate', def);

Compile the Generated S-Function for Simulation

After you generate the C-MEX S-function source file, to compile the S-function for simulation with Simulink®, call the function legacy_code() again with the first input set to 'compile'.

legacy_code('compile', def);
### Start Compiling rtwdemo_sfun_times_s16
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex96454812', '-c', '-outdir', '/tmp/Bdoc20b_1465442_59938/tpfeed7570_b6a2_4dda_9ed9_f9be620d2fa9', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/timesS16.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_times_s16.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex96454812', '/tmp/Bdoc20b_1465442_59938/tpfeed7570_b6a2_4dda_9ed9_f9be620d2fa9/timesS16.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_times_s16
### Exit

Generate a TLC Block File for Code Generation

After you compile the S-function and use it in simulation, you can call the function legacy_code() again with the first input set to 'sfcn_tlc_generate' to generate a TLC block file. The block file specifies how the generated code for a model calls the legacy code. If you do not generate a TLC block file and you try to generate code for a model that includes the S-function, code generation fails. The TLC block file for the S-function is: rtwdemo_sfun_times_s16.tlc.

legacy_code('sfcn_tlc_generate', def);

Generate an rtwmakecfg.m File for Code Generation

After you create the TLC block file, you can call the function legacy_code() again with the first input set to 'rtwmakecfg_generate' to generate an rtwmakecfg.m file to support code generation. If the required source and header files for the S-function are not in the same folder as the S-function, and you want to add these dependencies in the makefile produced during code generation, generate the rtwmakecfg.m file.

legacy_code('rtwmakecfg_generate', def);

Generate a Masked S-Function Block for Calling the Generated S-Function

After you compile the C-MEX S-function source, you can call the function legacy_code() again with the first input set to 'slblock_generate' to generate a masked S-function block that calls that S-function. The software places the block in a new model. From there you can copy it to an existing model.

legacy_code('slblock_generate', def);

Show the Integration of the Model with Legacy Code

The model rtwdemo_lct_fixpt_signals shows integration of the model with the legacy code. The subsystem TestFixpt serves as a harness for the call to the legacy C function via the generated S-function.

open_system('rtwdemo_lct_fixpt_signals')
open_system('rtwdemo_lct_fixpt_signals/TestFixpt')
sim('rtwdemo_lct_fixpt_signals')

Integrate External C Functions with Instance-Specific Persistent Memory

Integrate legacy C functions that use instance-specific persistent memory by using the Legacy Code Tool.

With the Legacy Code Tool, you can:

  • Provide the legacy function specification.

  • Generate a C-MEX S-function that calls the legacy code during simulation.

  • Compile and build the generated S-function for simulation.

  • Generate a TLC block file and optional rtwmakecfg.m file that specifies how the generated code for a model calls the legacy code.

Provide the Legacy Function Specification

Legacy Code Tool functions take a specific data structure or array of structures as the argument. You can initialize the data structure by calling the function legacy_code() using 'initialize' as the first input. After initializing the structure, assign its properties to values corresponding to the legacy code being integrated. For detailed help on the properties, call legacy_code('help'). The prototypes of the legacy functions being called in this example are:

void memory_bus_init(COUNTERBUS *mem, int32_T upper_sat, int32_T lower_sat);

void memory_bus_step(COUNTERBUS *input, COUNTERBUS *mem, COUNTERBUS *output);

mem is an instance-specific persistent memory for applying a one integration step delay. COUNTERBUS is a struct typedef defined in counterbus.h and implemented with a Simulink.Bus object in the base workspace. The legacy source code is in the files memory_bus.h, and memory_bus.c.

evalin('base','load rtwdemo_lct_data.mat')

% rtwdemo_sfun_work
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_work';
def.InitializeConditionsFcnSpec = ...
    'void memory_bus_init(COUNTERBUS work1[1], int32 p1, int32 p2)';
def.OutputFcnSpec = ...
    'void memory_bus_step(COUNTERBUS u1[1], COUNTERBUS work1[1], COUNTERBUS y1[1])';
def.HeaderFiles   = {'memory_bus.h'};
def.SourceFiles   = {'memory_bus.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};

Generate an S-Function for Simulation

To generate a C-MEX S-function according to the description provided by the input argument 'def', call the function legacy_code() again with the first input set to 'sfcn_cmex_generate'. The S-function calls the legacy functions during simulation. The source code for the S-function is in the file rtwdemo_sfun_work.c.

legacy_code('sfcn_cmex_generate', def);

Compile the Generated S-Function for Simulation

After you generate the C-MEX S-function source file, to compile the S-function for simulation with Simulink®, call the function legacy_code() again with the first input set to 'compile'.

legacy_code('compile', def);
### Start Compiling rtwdemo_sfun_work
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex38707886', '-c', '-outdir', '/tmp/Bdoc20b_1465442_59938/tp1d9f1305_b2ae_4295_8ed0_4ed5967afc8b', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/memory_bus.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_work.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex38707886', '/tmp/Bdoc20b_1465442_59938/tp1d9f1305_b2ae_4295_8ed0_4ed5967afc8b/memory_bus.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_work
### Exit

Generate a TLC Block File for Code Generation

After you compile the S-function and use it in simulation, you can call the function legacy_code() again with the first input set to 'sfcn_tlc_generate' to generate a TLC block file. The block file specifies how the generated code for a model calls the legacy code. If you do not generate a TLC block file and you try to generate code for a model that includes the S-function, code generation fails. The TLC block file for the S-function is: rtwdemo_sfun_work.tlc.

legacy_code('sfcn_tlc_generate', def);

Generate an rtwmakecfg.m File for Code Generation

After you create the TLC block file, you can call the function legacy_code() again with the first input set to 'rtwmakecfg_generate' to generate an rtwmakecfg.m file to support code generation. If the required source and header files for the S-function are not in the same folder as the S-function, and you want to add these dependencies in the makefile produced during code generation, generate the rtwmakecfg.m file.

legacy_code('rtwmakecfg_generate', def);

Generate a Masked S-Function Block for Calling the Generated S-Function

After you compile the C-MEX S-function source, you can call the function legacy_code() again with the first input set to 'slblock_generate' to generate a masked S-function block that calls that S-function. The software places the block in a new model. From there you can copy it to an existing model.

legacy_code('slblock_generate', def);

Show the Integration of the Model with Legacy Code

The model rtwdemo_lct_work shows integration of the model with the legacy code. The subsystem memory_bus serves as a harness for the call to the legacy C function.

open_system('rtwdemo_lct_work')
open_system('rtwdemo_lct_work/memory_bus')
sim('rtwdemo_lct_work')

Integrate External C Functions That Use Structure Arguments

Integrate legacy C functions with structure arguments that use Simulink® buses with the Legacy Code Tool.

With the Legacy Code Tool, you can:

  • Provide the legacy function specification.

  • Generate a C-MEX S-function that calls the legacy code during simulation.

  • Compile and build the generated S-function for simulation.

  • Generate a TLC block file and optional rtwmakecfg.m file that specifies how the generated code for a model calls the legacy code.

Provide the Legacy Function Specification

Legacy Code Tool functions take a specific data structure or array of structures as the argument. You can initialize the data structure by calling the function legacy_code() using 'initialize' as the first input. After initializing the structure, assign its properties to values corresponding to the legacy code being integrated. For detailed help on the properties, call legacy_code('help'). The prototype of the legacy functions being called in this example is:

counterbusFcn(COUNTERBUS *u1, int32_T u2, COUNTERBUS *y1, int32_T *y2)

COUNTERBUS is a struct typedef defined in counterbus.h and implemented with a Simulink.Bus object in the base workspace. The legacy source code is in the files counterbus.h, and counterbus.c.

evalin('base','load rtwdemo_lct_data.mat')

% rtwdemo_sfun_counterbus
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_counterbus';
def.OutputFcnSpec = ...
    'void counterbusFcn(COUNTERBUS u1[1], int32 u2, COUNTERBUS y1[1], int32 y2[1])';
def.HeaderFiles   = {'counterbus.h'};
def.SourceFiles   = {'counterbus.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};

Generate an S-Function for Simulation

To generate a C-MEX S-function according to the description provided by the input argument 'def', call the function legacy_code() again with the first input set to 'sfcn_cmex_generate'. The S-function calls the legacy functions during simulation. The source code for the S-function is in the file rtwdemo_sfun_counterbus.c.

legacy_code('sfcn_cmex_generate', def);

Compile the Generated S-Function for Simulation

After you generate the C-MEX S-function source file, to compile the S-function for simulation with Simulink®, call the function legacy_code() again with the first input set to 'compile'.

legacy_code('compile', def);
### Start Compiling rtwdemo_sfun_counterbus
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex90330074', '-c', '-outdir', '/tmp/Bdoc20b_1465442_59938/tp88a0b857_3a1a_42fe_bfde_4dfa484637a0', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/counterbus.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_counterbus.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex90330074', '/tmp/Bdoc20b_1465442_59938/tp88a0b857_3a1a_42fe_bfde_4dfa484637a0/counterbus.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_counterbus
### Exit

Generate a TLC Block File for Code Generation

After you compile the S-function and use it in simulation, you can call the function legacy_code() again with the first input set to 'sfcn_tlc_generate' to generate a TLC block file. The block file specifies how the generated code for a model calls the legacy code. If you do not generate a TLC block file and you try to generate code for a model that includes the S-function, code generation fails. The TLC block file for the S-function is: rtwdemo_sfun_counterbus.tlc.

legacy_code('sfcn_tlc_generate', def);

Generate an rtwmakecfg.m File for Code Generation

After you create the TLC block file, you can call the function legacy_code() again with the first input set to 'rtwmakecfg_generate' to generate an rtwmakecfg.m file to support code generation. If the required source and header files for the S-function are not in the same folder as the S-function, and you want to add these dependencies in the makefile produced during code generation, generate the rtwmakecfg.m file.

legacy_code('rtwmakecfg_generate', def);

Generate a Masked S-Function Block for Calling the Generated S-Function

After you compile the C-MEX S-function source, you can call the function legacy_code() again with the first input set to 'slblock_generate' to generate a masked S-function block that calls that S-function. The software places the block in a new model. From there you can copy it to an existing model.

legacy_code('slblock_generate', def);

Show the Integration of the Model with Legacy Code

The model rtwdemo_lct_bus shows integration of the model with the legacy code. The subsystem TestCounter serves as a harness for the call to the legacy C function.

open_system('rtwdemo_lct_bus')
open_system('rtwdemo_lct_bus/TestCounter')
sim('rtwdemo_lct_bus')

Integrate External C Functions That Pass Input and Output Arguments as Signals with Complex Data

Integrate legacy C functions using complex signals with the Legacy Code Tool.

With the Legacy Code Tool, you can:

  • Provide the legacy function specification.

  • Generate a C-MEX S-function that calls the legacy code during simulation.

  • Compile and build the generated S-function for simulation.

  • Generate a TLC block file and optional rtwmakecfg.m file that specifies how the generated code for a model calls the legacy code.

Provide the Legacy Function Specification

Legacy Code Tool functions take a specific data structure or array of structures as the argument. You can initialize the data structure by calling the function legacy_code() using 'initialize' as the first input. After initializing the structure, assign its properties to values corresponding to the legacy code being integrated. For detailed help on the properties, call legacy_code('help'). The prototype of the legacy functions being called in this example is:

void cplx_gain(creal_T *input, creal_T *gain, creal_T *output);

creal_T is the complex representation of a double. The legacy source code is in the files cplxgain.h, and cplxgain.c.

% rtwdemo_sfun_gain_scalar
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_cplx_gain';
def.OutputFcnSpec = ...
    ['void cplx_gain(complex<double> u1[1], '...
    'complex<double> p1[1], complex<double> y1[1])'];
def.HeaderFiles   = {'cplxgain.h'};
def.SourceFiles   = {'cplxgain.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};

Generate an S-Function for Simulation

To generate a C-MEX S-function according to the description provided by the input argument 'def', call the function legacy_code() again with the first input set to 'sfcn_cmex_generate'. The S-function calls the legacy functions during simulation. The source code for the S-function is in the file rtwdemo_sfun_cplx_gain.c.

legacy_code('sfcn_cmex_generate', def);

Compile the Generated S-Function for Simulation

After you generate the C-MEX S-function source file, to compile the S-function for simulation with Simulink®, call the function legacy_code() again with the first input set to 'compile'.

legacy_code('compile', def);
### Start Compiling rtwdemo_sfun_cplx_gain
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex97344681', '-c', '-outdir', '/tmp/Bdoc20b_1465442_59938/tp1dd24d36_0084_42a3_8810_2e34ae9e5dea', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/cplxgain.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_cplx_gain.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex97344681', '/tmp/Bdoc20b_1465442_59938/tp1dd24d36_0084_42a3_8810_2e34ae9e5dea/cplxgain.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_cplx_gain
### Exit

Generate a TLC Block File for Code Generation

After you compile the S-function and use it in simulation, you can call the function legacy_code() again with the first input set to 'sfcn_tlc_generate' to generate a TLC block file. The block file specifies how the generated code for a model calls the legacy code. If you do not generate a TLC block file and you try to generate code for a model that includes the S-function, code generation fails. The TLC block file for the S-function is: rtwdemo_sfun_cplx_gain.tlc.

legacy_code('sfcn_tlc_generate', def);

Generate an rtwmakecfg.m File for Code Generation

After you create the TLC block file, you can call the function legacy_code() again with the first input set to 'rtwmakecfg_generate' to generate an rtwmakecfg.m file to support code generation. If the required source and header files for the S-function are not in the same folder as the S-function, and you want to add these dependencies in the makefile produced during code generation, generate the rtwmakecfg.m file.

legacy_code('rtwmakecfg_generate', def);

Generate a Masked S-Function Block for Calling the Generated S-Function

After you compile the C-MEX S-function source, you can call the function legacy_code() again with the first input set to 'slblock_generate' to generate a masked S-function block that calls that S-function. The software places the block in a new model. From there you can copy it to an existing model.

legacy_code('slblock_generate', def);

Show the Integration of the Model with Legacy Code

The model rtwdemo_lct_cplxgain shows integration of the model with the legacy code. The subsystem complex_gain serves as a harness for the call to the legacy C function via the generate S-function.

if isempty(find_system('SearchDepth',0,'Name','rtwdemo_lct_cplxgain'))
    open_system('rtwdemo_lct_cplxgain')
    open_system('rtwdemo_lct_cplxgain/complex_gain')
    sim('rtwdemo_lct_cplxgain')
end

Integrate External C Functions That Pass Arguments That Have Inherited Dimensions

This example shows how to use the Legacy Code Tool to integrate legacy C functions whose arguments have inherited dimensions.

With the Legacy Code Tool, you can:

  • Provide the legacy function specification.

  • Generate a C-MEX S-function that calls the legacy code during simulation.

  • Compile and build the generated S-function for simulation.

  • Generate a TLC block file and optional rtwmakecfg.m file that specifies how the generated code for a model calls the legacy code.

Provide the Legacy Function Specification

Legacy Code Tool functions take a specific data structure or array of structures as the argument. You can initialize the data structure by calling the function legacy_code() using 'initialize' as the first input. After initializing the structure, assign its properties to values corresponding to the legacy code being integrated. For detailed help on the properties, call legacy_code('help'). The prototypes of the legacy functions being called in this example are:

  • void mat_add(real_T *u1, real_T *u2, int32_T nbRows, int32_T nbCols, real_T *y1)

  • void mat_mult(real_T *u1, real_T *u2, int32_T nbRows1, int32_T nbCols1, int32_T nbCols2, real_T *y1)

real_T is a typedef to double, and int32_T is a typedef to a 32-bit integer. The legacy source code is in the files mat_ops.h, and mat_ops.c.

defs = [];

% rtwdemo_sfun_mat_add
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_mat_add';
def.OutputFcnSpec = ['void mat_add(double u1[][], double u2[][], ' ...
                   'int32 u3, int32 u4, double y1[size(u1,1)][size(u1,2)])'];
def.HeaderFiles   = {'mat_ops.h'};
def.SourceFiles   = {'mat_ops.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};
defs = [defs; def];

% rtwdemo_sfun_mat_mult
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_mat_mult';
def.OutputFcnSpec =  ['void mat_mult(double u1[p1][p2], double u2[p2][p3], '...
                   'int32 p1, int32 p2, int32 p3, double y1[p1][p3])'];
def.HeaderFiles   = {'mat_ops.h'};
def.SourceFiles   = {'mat_ops.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};
defs = [defs; def];

Generate S-Functions for Simulation

To generate C-MEX S-functions according to the description provided by the input argument 'defs', call the function legacy_code() again with the first input set to 'sfcn_cmex_generate'. The S-functions call the legacy functions during simulation. The source code for the S-function is in the files rtwdemo_sfun_mat_add.c and rtwdemo_sfun_mat_mult.c.

legacy_code('sfcn_cmex_generate', defs);

Compile the Generated S-Functions for Simulation

After you generate the C-MEX S-function source files, to compile the S-functions for simulation with Simulink®, call the function legacy_code() again with the first input set to 'compile'.

legacy_code('compile', defs);
### Start Compiling rtwdemo_sfun_mat_add
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex89794148', '-c', '-outdir', '/tmp/Bdoc20b_1465442_59938/tp6b8a7cec_1174_4c44_adfc_ea1bc26c0e4d', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/mat_ops.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_mat_add.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex89794148', '/tmp/Bdoc20b_1465442_59938/tp6b8a7cec_1174_4c44_adfc_ea1bc26c0e4d/mat_ops.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_mat_add
### Exit

### Start Compiling rtwdemo_sfun_mat_mult
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex89794148', '-c', '-outdir', '/tmp/Bdoc20b_1465442_59938/tpb31b9957_2204_43e5_98de_07ed4700ce46', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/mat_ops.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_mat_mult.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex89794148', '/tmp/Bdoc20b_1465442_59938/tpb31b9957_2204_43e5_98de_07ed4700ce46/mat_ops.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_mat_mult
### Exit

Generate TLC Block Files for Code Generation

After you compile the S-functions and use them in simulation, you can call the function legacy_code() again with the first input set to 'sfcn_tlc_generate' to generate TLC block files. Block files specify how the generated code for a model calls the legacy code. If you do not generate TLC block files and you try to generate code for a model that includes the S-functions, code generation fails. The TLC block files for the S-functions are rtwdemo_sfun_mat_add.tlc and rtwdemo_sfun_mat_mult.tlc.

legacy_code('sfcn_tlc_generate', defs);

Generate an rtwmakecfg.m File for Code Generation

After you create the TLC block files, you can call the function legacy_code() again with the first input set to 'rtwmakecfg_generate' to generate an rtwmakecfg.m file to support code generation. If the required source and header files for the S-functions are not in the same folder as the S-functions, and you want to add these dependencies in the makefile produced during code generation, generate the rtwmakecfg.m file.

legacy_code('rtwmakecfg_generate', defs);

Generate Masked S-Function Blocks for Calling the Generated S-Functions

After you compile the C-MEX S-function source, you can call the function legacy_code() again with the first input set to 'slblock_generate' to generate masked S-function blocks that call the S-functions. The software places the blocks in a new model. From there you can copy them to an existing model

legacy_code('slblock_generate', defs);

Show the Generated Integration with Legacy Code

The model rtwdemo_lct_inherit_dims shows integration of the model with the legacy code. The subsystem TestMatOps serves as a harness for the calls to the legacy C functions, with unit delays serving to store the previous output values.

open_system('rtwdemo_lct_inherit_dims')
open_system('rtwdemo_lct_inherit_dims/TestMatOps')
sim('rtwdemo_lct_inherit_dims')

Integrate External C Functions That Pass Arguments as Multi-Dimensional Signals

This example shows how to use the Legacy Code Tool to integrate legacy C functions with multi-dimensional Signals.

With the Legacy Code Tool, you can:

  • Provide the legacy function specification.

  • Generate a C-MEX S-function that calls the legacy code during simulation.

  • Compile and build the generated S-function for simulation.

  • Generate a TLC block file and optional rtwmakecfg.m file that specifies how the generated code for a model calls the legacy code.

Provide the Legacy Function Specification

Legacy Code Tool functions take a specific data structure or array of structures as the argument. You can initialize the data structure by calling the function legacy_code() using 'initialize' as the first input. After initializing the structure, assign its properties to values corresponding to the legacy code being integrated. For detailed help on the properties, call legacy_code('help'). The prototype of the legacy functions being called in this example is:

void array3d_add(real_T *y1, real_T *u1, real_T *u2, int32_T nbRows, int32_T nbCols, int32_T nbPages);

real_T is a typedef to double, and int32_T is a typedef to a 32-bit integer. The legacy source code is in the files ndarray_ops.h, and ndarray_ops.c.

% rtwdemo_sfun_ndarray_add
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_ndarray_add';
def.OutputFcnSpec =...
    ['void array3d_add(double y1[size(u1,1)][size(u1,2)][size(u1,3)], ',...
    'double u1[][][], double u2[][][], ' ...
    'int32 size(u1,1), int32 size(u1,2), int32 size(u1,3))'];
def.HeaderFiles   = {'ndarray_ops.h'};
def.SourceFiles   = {'ndarray_ops.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};

y1 is a 3-D output signal of same dimensions as the 3-D input signal u1. Note that the last 3 arguments passed to the legacy function correspond to the number of element in each dimension of the 3-D input signal u1.

Generate an S-Function for Simulation

To generate a C-MEX S-function according to the description provided by the input argument 'def', call the function legacy_code() again with the first input set to 'sfcn_cmex_generate'. The S-function calls the legacy functions during simulation. The source code for the S-function is in the file rtwdemo_sfun_ndarray_add.c.

legacy_code('sfcn_cmex_generate', def);

Compile the Generated S-Function for Simulation

After you generate the C-MEX S-function source file, to compile the S-function for simulation with Simulink®, call the function legacy_code() again with the first input set to 'compile'.

legacy_code('compile', def);
### Start Compiling rtwdemo_sfun_ndarray_add
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_50501/tpa56c3ced/ex14927435', '-c', '-outdir', '/tmp/Bdoc20b_1465442_50501/tpd03f25b7_ed71_4ebc_9757_a9987b30fce3', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/ndarray_ops.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_ndarray_add.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_50501/tpa56c3ced/ex14927435', '/tmp/Bdoc20b_1465442_50501/tpd03f25b7_ed71_4ebc_9757_a9987b30fce3/ndarray_ops.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_ndarray_add
### Exit

Generate a TLC Block File for Code Generation

After you compile the S-function and use it in simulation, you can call the function legacy_code() again with the first input set to 'sfcn_tlc_generate' to generate a TLC block file. The block file specifies how the generated code for a model calls the legacy code. If you do not generate a TLC block file and you try to generate code for a model that includes the S-function, code generation fails. The TLC block file for the S-function is: rtwdemo_sfun_ndarray_add.tlc.

legacy_code('sfcn_tlc_generate', def);

Generate an rtwmakecfg.m File for Code Generation

After you create the TLC block file, you can call the function legacy_code() again with the first input set to 'rtwmakecfg_generate' to generate an rtwmakecfg.m file to support code generation. If the required source and header files for the S-function are not in the same folder as the S-function, and you want to add these dependencies in the makefile produced during code generation, generate the rtwmakecfg.m file.

legacy_code('rtwmakecfg_generate', def);

Generate a Masked S-Function Block for Calling the Generated S-Function

After you compile the C-MEX S-function source, you can call the function legacy_code() again with the first input set to 'slblock_generate' to generate a masked S-function block that calls that S-function. The software places the block in a new model. From there you can copy it to an existing model.

legacy_code('slblock_generate', def);

Showing the Generated Integration with Legacy Code

The model rtwdemo_lct_ndarray shows integration of the model with the legacy code. The subsystem ndarray_add serves as a harness for the call to the legacy C function.

open_system('rtwdemo_lct_ndarray')
open_system('rtwdemo_lct_ndarray/ndarray_add')
sim('rtwdemo_lct_ndarray')

Integrate External C Functions That Implement Start and Terminate Actions

Integrate legacy C functions that have start and terminate actions by using the Legacy Code Tool.

With the Legacy Code Tool, you can:

  • Provide the legacy function specification.

  • Generate a C-MEX S-function that calls the legacy code during simulation.

  • Compile and build the generated S-function for simulation.

  • Generate a TLC block file and optional rtwmakecfg.m file that specifies how the generated code for a model calls the legacy code.

Provide the Legacy Function Specification

Legacy Code Tool functions take a specific data structure or array of structures as the argument. You can initialize the data structure by calling the function legacy_code() using 'initialize' as the first input. After initializing the structure, assign its properties to values corresponding to the legacy code being integrated. For detailed help on the properties, call legacy_code('help'). The prototypes of the legacy functions being called in this example are:

  • void initFaultCounter(unsigned int *counter)

  • void openLogFile(void **fid)

  • void incAndLogFaultCounter(void *fid, unsigned int *counter, double time)

  • void closeLogFile(void **fid)

The legacy source code is in the files your_types.h, fault.h, and fault.c.

% rtwdemo_sfun_fault
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_fault';
def.InitializeConditionsFcnSpec  = 'initFaultCounter(uint32 work2[1])';
def.StartFcnSpec                 = 'openLogFile(void **work1)';
def.OutputFcnSpec                = ...
    'incAndLogFaultCounter(void *work1, uint32 work2[1], double u1)';
def.TerminateFcnSpec             = 'closeLogFile(void **work1)';
def.HeaderFiles                  = {'fault.h'};
def.SourceFiles                  = {'fault.c'};
def.IncPaths                     = {'rtwdemo_lct_src'};
def.SrcPaths                     = {'rtwdemo_lct_src'};
def.Options.useTlcWithAccel      = false;

Generate an S-Function for Simulation

To generate a C-MEX S-function according to the description provided by the input argument 'def', call the function legacy_code() again with the first input set to 'sfcn_cmex_generate'. The S-function calls the legacy functions during simulation. The source code for the S-function is in the file rtwdemo_sfun_fault.c.

legacy_code('sfcn_cmex_generate', def);

Compile the Generated S-Function for Simulation

After you generate the C-MEX S-function source file, to compile the S-function for simulation with Simulink®, call the function legacy_code() again with the first input set to 'compile'.

legacy_code('compile', def);
### Start Compiling rtwdemo_sfun_fault
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_50501/tpa56c3ced/ex46254423', '-c', '-outdir', '/tmp/Bdoc20b_1465442_50501/tp48618372_776a_4afe_8b3a_e2584433cfd0', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/fault.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_fault.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_50501/tpa56c3ced/ex46254423', '/tmp/Bdoc20b_1465442_50501/tp48618372_776a_4afe_8b3a_e2584433cfd0/fault.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_fault
### Exit

Generate a TLC Block File for Code Generation

After you compile the S-function and use it in simulation, you can call the function legacy_code() again with the first input set to 'sfcn_tlc_generate' to generate a TLC block file. The block file specifies how the generated code for a model calls the legacy code. If you do not generate a TLC block file and you try to generate code for a model that includes the S-function, code generation fails. The TLC block file for the S-function is: rtwdemo_sfun_fault.tlc.

legacy_code('sfcn_tlc_generate', def);

Generate an rtwmakecfg.m File for Code Generation

After you create the TLC block file, you can call the function legacy_code() again with the first input set to 'rtwmakecfg_generate' to generate an rtwmakecfg.m file to support code generation. If the required source and header files for the S-function are not in the same folder as the S-function, and you want to add these dependencies in the makefile produced during code generation, generate the rtwmakecfg.m file.

legacy_code('rtwmakecfg_generate', def);

Generate a Masked S-Function Block for Calling the Generated S-Function

After you compile the C-MEX S-function source, you can call the function legacy_code() again with the first input set to 'slblock_generate' to generate a masked S-function block that calls that S-function. The software places the block in a new model. From there you can copy it to an existing model.

legacy_code('slblock_generate', def);

Showing the Generated Integration with Legacy Code

The model rtwdemo_lct_start_term shows integration of the model with the legacy code. The subsystem TestFixpt serves as a harness for the call to the legacy C function, and the scope compares the output of the function with the output of the built-in Simulink® product block; the results should be identical.

open_system('rtwdemo_lct_start_term')
open_system('rtwdemo_lct_start_term/TestFault')
sim('rtwdemo_lct_start_term')

Integrate External C Functions That Implement N-Dimensional Table Lookups

Integrate legacy C functions that implement N-dimensional table lookups by using the Legacy Code Tool.

With the Legacy Code Tool, you can:

  • Provide the legacy function specification.

  • Generate a C-MEX S-function that calls the legacy code during simulation.

  • Compile and build the generated S-function for simulation.

  • Generate a TLC block file and optional rtwmakecfg.m file that specifies how the generated code for a model calls the legacy code.

Provide the Legacy Function Specification

Legacy Code Tool functions take a specific data structure or array of structures as the argument. You can initialize the data structure by calling the function legacy_code() using 'initialize' as the first input. After initializing the structure, assign its properties to values corresponding to the legacy code being integrated. For detailed help on the properties, call legacy_code('help'). The prototype of the legacy functions being called in this example is:

FLT directLookupTableND(const FLT *tableND, const UINT32 nbDims, const UINT32 *tableDims, const UINT32 *tableIdx)

FLT is a typedef to float, and UINT32 is a typedef to unsigned int32. The legacy source code is in the files your_types.h, lookupTable.h, and directLookupTableND.c.

defs = [];
evalin('base','load rtwdemo_lct_data.mat')

% rtwdemo_sfun_dlut3D
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_dlut3D';
def.OutputFcnSpec = 'single y1 = DirectLookupTable3D(single p1[][][], uint32 p2[3], uint32 u1[3])';
def.HeaderFiles   = {'lookupTable.h'};
def.SourceFiles   = {'directLookupTableND.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};
defs = [defs; def];

% rtwdemo_sfun_dlut4D
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_dlut4D';
def.OutputFcnSpec = 'single y1 = DirectLookupTable4D(single p1[][][][], uint32 p2[4], uint32 u1[4])';
def.HeaderFiles   = {'lookupTable.h'};
def.SourceFiles   = {'directLookupTableND.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};
defs = [defs; def];

Generate S-Functions for Simulation

To generate C-MEX S-functions according to the description provided by the input argument 'defs', call the function legacy_code() again. Set the first input to 'sfcn_cmex_generate'. The S-functions call the legacy functions during simulation. The source code for the S-functions is in the files rtwdemo_sfun_dlut3D.c and rtwdemo_sfun_dlut4D.c.

legacy_code('sfcn_cmex_generate', defs);

Compile the Generated S-Functions for Simulation

After you generate the C-MEX S-function source files, to compile the S-functions for simulation with Simulink®, call the function legacy_code() again. Set the first input to 'compile'.

legacy_code('compile', defs);
### Start Compiling rtwdemo_sfun_dlut3D
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_50501/tpa56c3ced/ex19426386', '-c', '-outdir', '/tmp/Bdoc20b_1465442_50501/tpc801ab37_411a_443d_9cae_c78fff19e554', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/directLookupTableND.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_dlut3D.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_50501/tpa56c3ced/ex19426386', '/tmp/Bdoc20b_1465442_50501/tpc801ab37_411a_443d_9cae_c78fff19e554/directLookupTableND.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_dlut3D
### Exit

### Start Compiling rtwdemo_sfun_dlut4D
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_50501/tpa56c3ced/ex19426386', '-c', '-outdir', '/tmp/Bdoc20b_1465442_50501/tp50e2bd81_d9d6_485f_93e3_cc7c7dc64f16', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/directLookupTableND.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_dlut4D.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_50501/tpa56c3ced/ex19426386', '/tmp/Bdoc20b_1465442_50501/tp50e2bd81_d9d6_485f_93e3_cc7c7dc64f16/directLookupTableND.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_dlut4D
### Exit

Generate TLC Block Files for Code Generation

After you compile the S-functions and use them in simulation, you can call the function legacy_code() again. Set the first input to 'sfcn_tlc_generate' to generate TLC block files. Block files specify how the generated code for a model calls the legacy code. If you do not generate TLC block files and you try to generate code for a model that includes the S-functions, code generation fails. The TLC block files for the S-functions are rtwdemo_sfun_dlut3D.tlc and rtwdemo_sfun_dlut4D.tlc.

legacy_code('sfcn_tlc_generate', defs);

Generate an rtwmakecfg.m File for Code Generation

After you create the TLC block files, you can call the function legacy_code() again. Set the first input to 'rtwmakecfg_generate' to generate an rtwmakecfg.m file to support code generation. If the required source and header files for the S-functions are not in the same folder as the S-functions, and you want to add these dependencies in the makefile produced during code generation, generate the rtwmakecfg.m file.

legacy_code('rtwmakecfg_generate', defs);

Generate Masked S-Function Blocks for Calling the Generated S-Functions

After you compile the C-MEX S-function source, you can call the function legacy_code() again. Set the first input to 'slblock_generate' to generate masked S-function blocks that call the S-functions. The software places the blocks in a new model. You can copy the blocks to an existing model.

legacy_code('slblock_generate', defs);

Show the Generated Integration with Legacy Code

The model rtwdemo_lct_lut shows integration of the model with the legacy code. The subsystem TestFixpt serves as a harness for the call to the legacy C function, and the Display blocks compare the output of the function with the output of the built-in Simulink® lookup blocks. The results are identical.

open_system('rtwdemo_lct_lut')
open_system('rtwdemo_lct_lut/TestLut1')
sim('rtwdemo_lct_lut')

Integrate External C Functions That Pass Arguments as Multi-Dimensional Signals

This example shows how to use the Legacy Code Tool to integrate legacy C functions with multi-dimensional Signals.

With the Legacy Code Tool, you can:

  • Provide the legacy function specification.

  • Generate a C-MEX S-function that calls the legacy code during simulation.

  • Compile and build the generated S-function for simulation.

  • Generate a TLC block file and optional rtwmakecfg.m file that specifies how the generated code for a model calls the legacy code.

Provide the Legacy Function Specification

Legacy Code Tool functions take a specific data structure or array of structures as the argument. You can initialize the data structure by calling the function legacy_code() using 'initialize' as the first input. After initializing the structure, assign its properties to values corresponding to the legacy code being integrated. For detailed help on the properties, call legacy_code('help'). The prototype of the legacy functions being called in this example is:

void array3d_add(real_T *y1, real_T *u1, real_T *u2, int32_T nbRows, int32_T nbCols, int32_T nbPages);

real_T is a typedef to double, and int32_T is a typedef to a 32-bit integer. The legacy source code is in the files ndarray_ops.h, and ndarray_ops.c.

% rtwdemo_sfun_ndarray_add
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_ndarray_add';
def.OutputFcnSpec =...
    ['void array3d_add(double y1[size(u1,1)][size(u1,2)][size(u1,3)], ',...
    'double u1[][][], double u2[][][], ' ...
    'int32 size(u1,1), int32 size(u1,2), int32 size(u1,3))'];
def.HeaderFiles   = {'ndarray_ops.h'};
def.SourceFiles   = {'ndarray_ops.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};

y1 is a 3-D output signal of same dimensions as the 3-D input signal u1. Note that the last 3 arguments passed to the legacy function correspond to the number of element in each dimension of the 3-D input signal u1.

Generate an S-Function for Simulation

To generate a C-MEX S-function according to the description provided by the input argument 'def', call the function legacy_code() again with the first input set to 'sfcn_cmex_generate'. The S-function calls the legacy functions during simulation. The source code for the S-function is in the file rtwdemo_sfun_ndarray_add.c.

legacy_code('sfcn_cmex_generate', def);

Compile the Generated S-Function for Simulation

After you generate the C-MEX S-function source file, to compile the S-function for simulation with Simulink®, call the function legacy_code() again with the first input set to 'compile'.

legacy_code('compile', def);
### Start Compiling rtwdemo_sfun_ndarray_add
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_50501/tpa56c3ced/ex14927435', '-c', '-outdir', '/tmp/Bdoc20b_1465442_50501/tpd03f25b7_ed71_4ebc_9757_a9987b30fce3', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/ndarray_ops.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_ndarray_add.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_50501/tpa56c3ced/ex14927435', '/tmp/Bdoc20b_1465442_50501/tpd03f25b7_ed71_4ebc_9757_a9987b30fce3/ndarray_ops.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_ndarray_add
### Exit

Generate a TLC Block File for Code Generation

After you compile the S-function and use it in simulation, you can call the function legacy_code() again with the first input set to 'sfcn_tlc_generate' to generate a TLC block file. The block file specifies how the generated code for a model calls the legacy code. If you do not generate a TLC block file and you try to generate code for a model that includes the S-function, code generation fails. The TLC block file for the S-function is: rtwdemo_sfun_ndarray_add.tlc.

legacy_code('sfcn_tlc_generate', def);

Generate an rtwmakecfg.m File for Code Generation

After you create the TLC block file, you can call the function legacy_code() again with the first input set to 'rtwmakecfg_generate' to generate an rtwmakecfg.m file to support code generation. If the required source and header files for the S-function are not in the same folder as the S-function, and you want to add these dependencies in the makefile produced during code generation, generate the rtwmakecfg.m file.

legacy_code('rtwmakecfg_generate', def);

Generate a Masked S-Function Block for Calling the Generated S-Function

After you compile the C-MEX S-function source, you can call the function legacy_code() again with the first input set to 'slblock_generate' to generate a masked S-function block that calls that S-function. The software places the block in a new model. From there you can copy it to an existing model.

legacy_code('slblock_generate', def);

Showing the Generated Integration with Legacy Code

The model rtwdemo_lct_ndarray shows integration of the model with the legacy code. The subsystem ndarray_add serves as a harness for the call to the legacy C function.

open_system('rtwdemo_lct_ndarray')
open_system('rtwdemo_lct_ndarray/ndarray_add')
sim('rtwdemo_lct_ndarray')

Integrate External C Functions with a Block Sample Time Specified, Inherited, and Parameterized

This example shows how to use the Legacy Code Tool to integrate legacy C functions with the block's sample time specified, inherited and parameterized.

With the Legacy Code Tool, you can:

  • Provide the legacy function specification.

  • Generate a C-MEX S-function that calls the legacy code during simulation.

  • Compile and build the generated S-function for simulation.

  • Generate a TLC block file and optional rtwmakecfg.m file that specifies how the generated code for a model calls the legacy code.

Provide the Legacy Function Specification

Legacy Code Tool functions take a specific data structure or array of structures as the argument. You can initialize the data structure by calling the function legacy_code() using 'initialize' as the first input. After initializing the structure, assign its properties to values corresponding to the legacy code being integrated. For detailed help on the properties, call legacy_code('help'). The prototype of the legacy functions being called in this example is:

FLT gainScalar(const FLT in, const FLT gain)

FLT is a typedef to float. The legacy source code is in the files your_types.h, gain.h, and gainScalar.c.

defs = [];

% rtwdemo_sfun_st_inherited
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_st_inherited';
def.OutputFcnSpec = 'single y1 = gainScalar(single u1, single p1)';
def.HeaderFiles   = {'gain.h'};
def.SourceFiles   = {'gainScalar.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};
defs = [defs; def];

% rtwdemo_sfun_st_fixed
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_st_fixed';
def.OutputFcnSpec = 'single y1 = gainScalar(single u1, single p1)';
def.HeaderFiles   = {'gain.h'};
def.SourceFiles   = {'gainScalar.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};
def.SampleTime    = [2 1];
defs = [defs; def];

% rtwdemo_sfun_st_parameterized
def = legacy_code('initialize');
def.SFunctionName = 'rtwdemo_sfun_st_parameterized';
def.OutputFcnSpec = 'single y1 = gainScalar(single u1, single p1)';
def.HeaderFiles   = {'gain.h'};
def.SourceFiles   = {'gainScalar.c'};
def.IncPaths      = {'rtwdemo_lct_src'};
def.SrcPaths      = {'rtwdemo_lct_src'};
def.SampleTime    = 'parameterized';
defs = [defs; def];

Generate S-Functions for Simulation

To generate C-MEX S-functions according to the description provided by the input argument 'defs', call the function legacy_code() again with the first input set to 'sfcn_cmex_generate'. The S-functions call the legacy functions during simulation. The source code for the S-functions is in the files rtwdemo_sfun_st_inherited.c and rtwdemo_sfun_st_fixed.c. rtwdemo_sfun_st_parameterized.c.

legacy_code('sfcn_cmex_generate', defs);

Compile the Generated S-Functions for Simulation

After you generate the C-MEX S-function source files, to compile the S-functions for simulation with Simulink®, call the function legacy_code() again with the first input set to 'compile'.

legacy_code('compile', defs);
### Start Compiling rtwdemo_sfun_st_inherited
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex74504488', '-c', '-outdir', '/tmp/Bdoc20b_1465442_59938/tpabcf5c2d_60af_4daf_adc8_612f6a269082', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/gainScalar.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_st_inherited.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex74504488', '/tmp/Bdoc20b_1465442_59938/tpabcf5c2d_60af_4daf_adc8_612f6a269082/gainScalar.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_st_inherited
### Exit

### Start Compiling rtwdemo_sfun_st_fixed
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex74504488', '-c', '-outdir', '/tmp/Bdoc20b_1465442_59938/tp04d8c1e7_032f_4a10_9ce3_e13bd3d5e3dd', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/gainScalar.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_st_fixed.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex74504488', '/tmp/Bdoc20b_1465442_59938/tp04d8c1e7_032f_4a10_9ce3_e13bd3d5e3dd/gainScalar.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_st_fixed
### Exit

### Start Compiling rtwdemo_sfun_st_parameterized
    mex('-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex74504488', '-c', '-outdir', '/tmp/Bdoc20b_1465442_59938/tpa80f921e_bbba_428b_82df_20ed6254c645', '/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src/gainScalar.c')
Building with 'gcc'.
MEX completed successfully.
    mex('rtwdemo_sfun_st_parameterized.c', '-I/mathworks/devel/bat/Bdoc20b/build/matlab/toolbox/rtw/rtwdemos/rtwdemo_lct_src', '-I/tmp/Bdoc20b_1465442_59938/tp8eb0d42c/ex74504488', '/tmp/Bdoc20b_1465442_59938/tpa80f921e_bbba_428b_82df_20ed6254c645/gainScalar.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling rtwdemo_sfun_st_parameterized
### Exit

Generate TLC Block Files for Code Generation

After you compile the S-functions and use them in simulation, you can call the function legacy_code() again with the first input set to 'sfcn_tlc_generate' to generate TLC block files. Block files specify how the generated code for a model calls the legacy code. If you do not generate TLC block files and you try to generate code for a model that includes the S-functions, code generation fails. The TLC block files for the S-functions are rtwdemo_sfun_st_inherited.tlc and rtwdemo_sfun_st_fixed.tlc. rtwdemo_sfun_st_parameterized.tlc.

legacy_code('sfcn_tlc_generate', defs);

Generate an rtwmakecfg.m File for Code Generation

After you create the TLC block files, you can call the function legacy_code() again with the first input set to 'rtwmakecfg_generate' to generate an rtwmakecfg.m file to support code generation. If the required source and header files for the S-functions are not in the same folder as the S-functions, and you want to add these dependencies in the makefile produced during code generation, generate the rtwmakecfg.m file.

legacy_code('rtwmakecfg_generate', defs);

Generate Masked S-Function Blocks for Calling the Generated S-Functions

After you compile the C-MEX S-function source, you can call the function legacy_code() again with the first input set to 'slblock_generate' to generate masked S-function blocks that call the S-functions. The software places the blocks in a new model. From there you can copy them to an existing model.

legacy_code('slblock_generate', defs);

Show the Generated Integration with Legacy Code

The model rtwdemo_lct_sampletime shows integration of the model with the legacy code. The subsystem sample_time serves as a harness for the calls to the legacy C functions, with unit delays serving to store the previous output values.

open_system('rtwdemo_lct_sampletime')
open_system('rtwdemo_lct_sampletime/sample_time')
sim('rtwdemo_lct_sampletime')

See Also

Related Topics