Writing S-Functions | ![]() ![]() |
Example of an Ada S-Function
This section presents an example of a basic Ada S-function that you can use as a model when creating your own Ada S-functions. The example is the timestwo
S-function example that comes with Simulink (see matlabroot
/simulink/ada/examples/timestwo.ads
and matlabroot
/simulink/ada/examples/timestwo.adb
). This S-function outputs twice its input.
The following model uses the timestwo
S-function to double the amplitude of a sine wave and plot it in a scope.
The block dialog for the S-function specifies timestwo
as the S-function name; the parameters field is empty.
The timestwo
S-function contains the S-function callback methods shown in this figure.
The source code for the timestwo S-function comprises two parts:
The following sections explain each of these parts.
Timestwo Package Specification
The timestwo
package specification, timestwo.ads
, contains the following code.
-- The Simulink API for Ada S-Function with Simulink; use Simulink; package Times_Two is -- The S_FUNCTION_NAME has to be defined as a constant string. Note that -- the name of the S-Function (ada_times_two) is different from the name -- of this package (times_two). We do this so that it is easy to identify -- this example S-Function in the MATLAB workspace. Normally you would use -- the same name for S_FUNCTION_NAME and the package. -- S_FUNCTION_NAME : constant String := "ada_times_two"; -- Every S-Function is required to have the "mdlInitializeSizes" method. -- This method needs to be exported as shown below, with the exported name -- being "mdlInitializeSizes". -- procedure mdlInitializeSizes(S : in SimStruct); pragma Export(C, mdlInitializeSizes, "mdlInitializeSizes"); procedure mdlOutputs(S : in SimStruct; TID : in Integer); pragma Export(C, mdlOutputs, "mdlOutputs"); end Times_Two;
The package specification begins by specifying that the S-function uses the Simulink
package.
The Simulink package defines Ada procedures for accessing the internal data structure (SimStruct) that Simulink maintains for each S-function (see SimStruct Functions).
Next the specification specifies the name of the S-function.
The name ada_times_two
serves to distinguish the MEX-file generated from Ada source from those generated from the timestwo
source coded in other languages.
Finally the specification specifies the callback methods implemented by the timestwo
S-function.
procedure mdlInitializeSizes(S : in SimStruct); pragma Export(C, mdlInitializeSizes, "mdlInitializeSizes"); procedure mdlOutputs(S : in SimStruct; TID : in Integer); pragma Export(C, mdlOutputs, "mdlOutputs");
The specification specifies that the Ada compiler should compile each method as a C-callable function. This is because the Simulink engine assumes that callback methods are C functions.
The timestwo
package body, timestwo.adb
, contains
with Simulink; use Simulink; with Ada.Exceptions; use Ada.Exceptions; package body Times_Two is -- Function: mdlInitializeSizes --------------------------------------------- -- Abstract: -- Setup the input and output port attrubouts for this S-Function. -- procedure mdlInitializeSizes(S : in SimStruct) is begin -- Set the input port attributes -- ssSetNumInputPorts( S, 1); ssSetInputPortWidth( S, 0, DYNAMICALLY_SIZED); ssSetInputPortDataType( S, 0, SS_DOUBLE); ssSetInputPortDirectFeedThrough(S, 0, TRUE); ssSetInputPortOverWritable( S, 0, FALSE); ssSetInputPortOptimizationLevel(S, 0, 3); -- Set the output port attributes -- ssSetNumOutputPorts( S, 1); ssSetOutputPortWidth( S, 0, DYNAMICALLY_SIZED); ssSetOutputPortDataType( S, 0, SS_DOUBLE); ssSetOutputPortOptimizationLevel(S, 0, 3); -- Set the block sample time. ssSetSampleTime( S, INHERITED_SAMPLE_TIME); exception when E : others => if ssGetErrorStatus(S) = "" then ssSetErrorStatus(S, "Exception occured in mdlInitializeSizes. " & "Name: " & Exception_Name(E) & ", " & "Message: " & Exception_Message(E) & " and " & "Information: " & Exception_Information(E)); end if; end mdlInitializeSizes; -- Function: mdlOutputs ----------------------------------------------------- -- Abstract: -- Compute the S-Function's output, given its input: y = 2 * u -- procedure mdlOutputs(S : in SimStruct; TID : in Integer) is uWidth : Integer := ssGetInputPortWidth(S,0); U : array(0 .. uWidth-1) of Real_T; for U'Address use ssGetInputPortSignalAddress(S,0); yWidth : Integer := ssGetOutputPortWidth(S,0); Y : array(0 .. yWidth-1) of Real_T; for Y'Address use ssGetOutputPortSignalAddress(S,0); begin if uWidth = 1 then for Idx in 0 .. yWidth-1 loop Y(Idx) := 2.0 * U(0); end loop; else for Idx in 0 .. yWidth-1 loop Y(Idx) := 2.0 * U(Idx); end loop; end if; exception when E : others => if ssGetErrorStatus(S) = "" then ssSetErrorStatus(S, "Exception occured in mdlOutputs. " & "Name: " & Exception_Name(E) & ", " & "Message: " & Exception_Message(E) & " and " & "Information: " & Exception_Information(E)); end if; end mdlOutputs; end Times_Two;
The package body contains implementations of the callback methods needed to implement the timestwo
example.
mdlInitializeSizes
Simulink calls mdlInitializeSizes
to inquire about the number of input and output ports, the sizes of the ports, and any other objects (such as the number of states) needed by the S-function.
The timestwo
implementation of mdlInitializeSizes
uses SimStruct functions defined in the Simulink package to specify the following size information:
Finally the method provides an exception handler to handle any errors that occur in invoking the SimStruct functions.
mdlOutputs
Simulink calls mdlOutputs at each time step to calculate a block's outputs. The timestwo
implementation of mdlOutputs
takes the input, multiplies it by 2, and writes the answer to the output.
The timestwo
implementation of the mdlOutputs
method uses the SimStruct functions ssGetInputPortWidth and ssGetInputPortSignalAddress to access the input signal.
uWidth : Integer := ssGetInputPortWidth(S,0); U : array(0 .. uWidth-1) of Real_T; for U'Address use ssGetInputPortSignalAddress(S,0);
Similarly, the mdlOutputs
method uses the functions ssGetOutputPortWidth
and ssGetOutputPortSignalAddress
to access the output signal.
yWidth : Integer := ssGetOutputPortWidth(S,0); Y : array(0 .. yWidth-1) of Real_T; for Y'Address use ssGetOutputPortSignalAddress(S,0);
Finally the method loops over the inputs to compute the outputs.
Building the Timestwo Example
To build this S-function into Simulink, enter
![]() | Building an Ada S-Function | Creating C++ S-Functions | ![]() |