Write Wrapper S-Function and TLC Files
Create S-functions that work seamlessly with the Simulink® and code generator products by using the wrapper concept. You can:
Interface your algorithms in Simulink models by writing MEX S-function wrappers (
).sfunction.mexDirect the code generator to insert your algorithm into the generated code by creating a TLC S-function wrapper (
).sfunction.tlc
MEX S-Function Wrapper
Creating S-functions by using an S-function wrapper enables you to insert C/C++ code algorithms in Simulink models and the generated code with little or no change to your original C/C++ function. A MEX S-function wrapper is an S-function that calls code, which resides in another module.
Note
Use a MEX S-function wrapper only in the MATLAB® version in which you created the wrapper.
Suppose that you have an algorithm (that is, a C function) called
my_alg that resides in the file my_alg.c.
You can integrate my_alg into a Simulink model by creating a MEX S-function wrapper (for example,
wrapsfcn.c). A Simulink model can then call my_alg from an S-Function
block. The Simulink S-function contains a set of empty functions that the Simulink engine requires for various API related purposes. For example,
although only mdlOutputs calls my_alg, the
engine calls mdlTerminate, even though this S-function routine
performs no action.
You can embed the call to my_alg in the generated code by
creating a TLC S-function wrapper (for example, wrapsfcn.tlc).
You can eliminate the empty function calls. You can avoid the overhead of executing
the mdlOutputs function and you can then eliminate the
my_alg function.
Wrapper S-functions are useful when you are creating algorithms that are procedural or when you are integrating legacy code into a Simulink model. If you want to create code that is:
Interpretive in nature (that is, highly parameterized by operating modes)
Heavily optimized (that is, no extra tests to decide what mode the code is operating in)
then you must create a fully inlined TLC file for your S-function.
The next figure shows the wrapper S-function concept.

Using an S-function wrapper to import algorithms into your Simulink model means that the S-function serves as an interface that calls your
C/C++ algorithms from mdlOutputs. You can quickly integrate
large standalone C/C++ programs into your model without having to change the
code.
This sample model includes an S-function wrapper.

Two files are associated with the wrapsfcn block: the
S-function wrapper and the C/C++ code that contains the algorithm. The first three
statements:
Define the name of the S-function (what you enter in the Simulink S-Function block dialog box).
Specify that the S-function is using the level 2 format.
Provide access to the
SimStructdata structure.SimStructcontains pointers to data used during simulation and code generation and defines macros that store data in and retrieve data from theSimStruct.
#define S_FUNCTION_NAME wrapsfcn
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"
extern real_T my_alg(real_T u); /* Declare my_alg as extern */
/*
* mdlInitializeSizes - initialize the sizes array
*/
static void mdlInitializeSizes(SimStruct *S)
{
ssSetNumSFcnParams( S, 0); /*number of input arguments*/
if (!ssSetNumInputPorts(S, 1)) return;
ssSetInputPortWidth(S, 0, 1);
ssSetInputPortDirectFeedThrough(S, 0, 1);
if (!ssSetNumOutputPorts(S,1)) return;
ssSetOutputPortWidth(S, 0, 1);
ssSetNumSampleTimes( S, 1);
}
/*
* mdlInitializeSampleTimes - indicate that this S-function runs
* at the rate of the source (driving block)
*/
static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);
ssSetOffsetTime(S, 0, 0.0);
}
/*
* mdlOutputs - compute the outputs by calling my_alg, which
* resides in another module, my_alg.c
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
real_T *y = ssGetOutputPortRealSignal(S,0);
*y = my_alg(*uPtrs[0]); /* Call my_alg in mdlOutputs */
}
/*
* mdlTerminate - called when the simulation is terminated.
*/
static void mdlTerminate(SimStruct *S)
{
}
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */
#include "simulink.c" /* MEX-file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endifFor more information, see Templates for C S-Functions.
The S-function routine mdlOutputs contains a function call to
my_alg, which is the C function containing the algorithm
that the S-function performs. For my_alg.c, the code is:
#ifdef MATLAB_MEX_FILE
#include "tmwtypes.h"
#else
#include "rtwtypes.h"
#endif
real_T my_alg(real_T u)
{
return(u * 2.0);
}For more information, see Manage Build Process File Dependencies.
The wrapper S-function wrapsfcn calls
my_alg, which computes u * 2.0. To build
wrapsfcn.mex, use this command:
mex wrapsfcn.c my_alg.c
TLC S-Function Wrapper
A TLC S-function wrapper is a TLC file that specifies how the code generator calls
your code. For example, you can inline the call to my_alg in
the mdlOutputs section of the generated code. In the MEX S-Function Wrapper example, the call to my_alg
is embedded in the mdlOutputs section as:
*y = my_alg(*uPtrs[0]);
When you are creating a TLC S-function wrapper, the goal is to embed the same type of call in the generated code.
Look at how the code generator executes S-functions that are not inlined. A
noninlined S-function is identified by the absence of the file
and the
existence of sfunction.tlc. When
generating code for a noninlined S-function, the code generator produces a call to
sfunction.mexmdlOutputs through a function pointer that, in this
example, then calls my_alg.
The wrapper example contains one S-function, wrapsfcn.mex. You
must compile and link an additional module, my_alg, with the
generated code. At the MATLAB command prompt, enter:
set_param('wrapper/S-Function','SFunctionModules','my_alg')
Code Overhead for Noninlined S-Functions
The code generated when using grt.tlc as the system target file
without
wrapsfcn.tlc is:
<Generated code comments for wrapper model with noninlined wrapsfcn S-function>
#include <math.h>
#include <string.h>
#include "wrapper.h"
#include "wrapper.prm"
/* Start the model */
void mdlStart(void)
{
/* (start code not required) */
}
/* Compute block outputs */
void mdlOutputs(int_T tid)
{
/* Sin Block: <Root>/Sin */
rtB.Sin = rtP.Sin.Amplitude *
sin(rtP.Sin.Frequency * ssGetT(rtS) + rtP.Sin.Phase);
/* Level2 S-Function Block: <Root>/S-Function (wrapsfcn) */
{
/* Noninlined S-functions create a SimStruct object and
* generate a call to S-function routine mdlOutputs
*/
SimStruct *rts = ssGetSFunction(rtS, 0);
sfcnOutputs(rts, tid);
}
/* Outport Block: <Root>/Out */
rtY.Out = rtB.S_Function;
}
/* Perform model update */
void mdlUpdate(int_T tid)
{
/* (update code not required) */
}
/* Terminate function */
void mdlTerminate(void)
{
/* Level2 S-Function Block: <Root>/S-Function (wrapsfcn) */
{
/* Noninlined S-functions require a SimStruct object and
* the call to S-function routine mdlTerminate
*/
SimStruct *rts = ssGetSFunction(rtS, 0);
sfcnTerminate(rts);
}
}
#include "wrapper.reg"
/* [EOF] wrapper.c */The wrapper.reg generated file contains the initialization of
the SimStruct for the wrapper S-Function block. There is one
child SimStruct for each S-Function block in your model. You can
significantly reduce this overhead by creating a TLC wrapper for the
S-function.
Inline a Wrapper S-Function
The generated code makes the call to your S-function,
wrapsfcn.c, in mdlOutputs by using this
code:
SimStruct *rts = ssGetSFunction(rtS, 0); sfcnOutputs(rts, tid);
This call has computational overhead associated with it. The Simulink engine creates a SimStruct data structure for the
S-Function block. The code generator constructs a call through a function pointer to
execute mdlOutputs, then mdlOutputs calls
my_alg. By inlining the call to your C/C++ algorithm,
my_alg, you can eliminate both the
SimStruct and the extra function call, thereby improving the
efficiency and reducing the size of the generated code.
Inlining a wrapper S-function requires an
file for the
S-function. The TLC file must contain the function call to
sfunction.tlcmy_alg. The figure shows the relationships between the
algorithm, the wrapper S-function, and the
file.sfunction.tlc

To inline the call to my_alg, place your function call in an
file with the
same name as the S-function (in this example, sfunction.tlcwrapsfcn.tlc). The
Target Language Compiler overrides the default method of placing calls to your
S-function in the generated code.
This code is the TLC file wrapsfcn.tlc that inlines
wrapsfcn.c:
%% File : wrapsfcn.tlc %% Abstract: %% Example inlined tlc file for S-function wrapsfcn.c %% %implements "wrapsfcn" "C" %% Function: BlockTypeSetup ==================================================== %% Abstract: %% Create function prototype in model.h as: %% "extern real_T my_alg(real_T u);" %% %function BlockTypeSetup(block, system) void %openfile buffer extern real_T my_alg(real_T u); /* This line is placed in wrapper.h */ %closefile buffer %<LibCacheFunctionPrototype(buffer)> %endfunction %% BlockTypeSetup %% Function: Outputs =========================================================== %% Abstract: %% y = my_alg( u ); %% %function Outputs(block, system) Output /* %<Type> Block: %<Name> */ %assign u = LibBlockInputSignal(0, "", "", 0) %assign y = LibBlockOutputSignal(0, "", "", 0) %% PROVIDE THE CALLING STATEMENT FOR "algorithm" %% The following line is expanded and placed in mdlOutputs within wrapper.c %<y> = my_alg(%<u>); %endfunction %% Outputs
The first section of this code inlines the wrapsfcn S-Function
block and generates the code in C:
%implements "wrapsfcn" "C"
The next task is to inform the code generator that the routine
my_alg must be declared as external in the generated
wrapper.h file for any
wrapsfcn S-Function blocks in the model. Do this declaration once
for all
wrapsfcn S-Function blocks by using the
BlockTypeSetup function. In this function, you direct the
Target Language Compiler to create a buffer and cache the my_alg
as extern in the wrapper.h generated header
file.
The final step is the inlining of the call to the function
my_alg. The Outputs function inlines
the call. In this function, you access the block input and output and place a direct
call to my_alg. The call is embedded in
wrapper.c.
The Inlined Code
The code generated when you inline your wrapper S-function is similar to the
default generated code. The mdlTerminate function does not
contain a call to an empty function and the mdlOutputs function
now directly calls my_alg.
void mdlOutputs(int_T tid)
{
/* Sin Block: <Root>/Sin */
rtB.Sin = rtP.Sin.Amplitude *
sin(rtP.Sin.Frequency * ssGetT(rtS) + rtP.Sin.Phase);
/* S-Function Block: <Root>/S-Function */
rtB.S_Function = my_alg(rtB.Sin); /* Inlined call to my_alg */
/* Outport Block: <Root>/Out */
rtY.Out = rtB.S_Function;
}wrapper.reg does not create a child
SimStruct for the S-function because the generated code is
calling my_alg directly, eliminating over 1 KB of memory
usage.