MATLAB: Developing and Building S-Functions for Simulink® that Incorporate Ada Code

How can I develop and build S-Functions for Simulink that Incorporate Ada Code?

Best Answer

Section 1: IntroductionThis document describes how to invoke algorithms written in Ada within Simulink 7.5 (R2010a) and later via the creation and compilation of S-Functions. Though the Ada S-Function API is now deprecated, the extensive C Mex S-Function  API for interfacing external tools and code to Simulink can be used to interface to Ada code. Files and examples are provided to facilitate this procedure. The document will be most useful to those familiar with Simulink software, S-Functions, the Ada language, and the GNAT family of Ada compilers.\n\n\n\n

  1. Download attached file ada_sfcn.zip or ada_sfcn.tgz.
  2. Extract the files to a folder.
  3. Open MATLAB and set the current working directory to that folder.
  4. Ensure that a GNAT compiler is on your system path.
  5. Build and test the examples with the command test_ada_sfcn_demos.
  6. Verify the creation of 4 .mex files in your working directory.
  7. Open and run the Simulink models in the /ada_sfcn_demos subdirectory.
\nThe techniques presented in this document require developing S-Functions in Ada as described in Section 3. If modification of your Ada code and/or creation of an Ada S-Function wrapper is undesirable, you may consider invoking Ada code within a skeleton C S-Function:\n
  1. Write an S-Function in C that:\n
    1. defines the mdl* callback functions that Simulink will call during simulation,
    2. uses the documented ss* API to access the SimStruct, and
    3. calls algorithms implemented in Ada.
  2. Use the Ada Export pragma to make procedures callable from C.
This alternative approach is analogous to that of 
, whose documentation provides further details on the process.\n\n\nSection 2: Building a MEX file for an S-Function incorporating Ada codeIn the following two sections, we describe how to use the provided files to build Simulink S-Functions that incorporate Ada code. Even though the interface code and examples are expected to work "out-of the-box," the primary purpose of this document and the included files is to illustrate how:\n
  • The C-Mex S-Function API can be accessed from Ada code, including access to inputs, outputs, parameters and work vectors
  • To invoke the Ada and C compilers to generate the object code and then link the object code into a dynamic library (DLL) that is recognized by Simulink as C-Mex S-Function.
We recommend that the code in these files be studied and modified to suit the user's Ada needs as well as their development environment. Modifications would certainly be needed if the GNAT tool chain is not being used.\n
Call the MATLAB function build_ada_sfcn with the name of an Ada specification (ads) file to build a binary MEX file:
build_ada_sfcn src.ads [options]
This command compiles the Ada code, compiles the provided C interface file sl_ada_entry.c, and links the generated objects into a shared library. The command is functionally equivalent to the deprecated mex -ada command that was available prior to Simulink 7.5 (R2010a). When calling build_ada_sfcn, make sure that the specification file is in the current working directory or that the full path to the file is supplied. Also note that the GNAT tool chain must be on the execution path. The following options may follow the source filename: 
 
OptionMeaningDefault-outdir dirCreate the MEX file in dir.Create MEX file in current directory.-vCompile with verbose flag.Compile without verbose flag.-vCompile with debug flag.Compile without debug flag.-I dir or -IdirAdd dir to Ada source and object search paths, and to C include path.-aI dir or -aIdirAdd dir to Ada source and object search paths, and to C include path.\n\n\nSection 3: Writing an S-Function in AdaIn order to use build_ada_sfcn, the Ada specification file must be written as an S-Function. An Ada S-Function is an Ada package containing procedures that Simulink calls during simulation. The procedures take an argument S of type SimStruct, provided by package Simulink. The package exports each procedure so it can be called from C. The package also contains a constant string S_FUNCTION_NAME containing the name of the S-Function.\n
For example, here is the specification file times_two.ads, with comments omitted to save space:
with Simulink; use Simulink;
package Times_Two is
S_FUNCTION_NAME : constant String := "ada_times_two";
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 corresponding body is times_two.adb:
with Simulink; use Simulink;
with Ada.Exceptions; use Ada.Exceptions;
package body Times_Two is
procedure mdlInitializeSizes(S : in SimStruct) is
begin
-- Set 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 output port attributes.
ssSetNumOutputPorts( S, 1);
ssSetOutputPortWidth( S, 0, DYNAMICALLY_SIZED);
ssSetOutputPortDataType( S, 0, SS_DOUBLE);
ssSetOutputPortOptimizationLevel(S, 0, 3);
-- Set 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;
procedure mdlOutputs(S : in SimStruct; TID : in Integer) is
-- Declare block input.
uWidth : Integer := ssGetInputPortWidth(S,0);
U : array(0 .. uWidth-1) of Real_T;
for U'Address use ssGetInputPortSignalAddress(S,0);
-- Declare block output.
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 -- Expand scalar input to width of output.
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;
Procedure mdlInitializeSizes is required. The Simulink engine calls the following procedures if the Ada S-Function exports them:
  • mdlCheckParameters
  • mdlSetWorkWidths
  • mdlStart
  • mdlInitCond
  • mdlProcessParameters
  • mdlOutputs
  • mdlUpdate
  • mdlDerivatives
  • mdlTerminate
\nSection 4: Answers to anticipated questions\nWe have tested with GNAT 3.15p on 32-bit Windows XP and with GNAT 4.3.2 on 64-bit Linux. You can build an Ada S-Function on any platform that supports both Simulink and GNAT.\n\n\n
  1. Find the S-Function name and the exported mdl functions in the specification.
  2. Compile sl_ada_entry.c, using a -D option for each mdl function found.
  3. Compile the Ada package with gnatmake.
  4. Create the shared library:\n
    • On a Windows platform, create a DLL file using gnatdll.
    • On a UNIX platform, bind the compiled objects with gnatbind, then link them with gnatlink.
Look at the comments and commands in build_ada_sfcn.m for additional details. Use the -v option to see the options and switches used with each command.\n\n\nYes. Modify build_ada_sfcn.m or create a similar MATLAB function for your compiler. Replace the calls to gcc, gnatmake, and gnatbind or gnatdll with the analogous commands for your tool chain.\n\n\nModify build_ada_sfcn.m or create a similar MATLAB function with the switches you want to use.\n\n\nHow Simulink calls S-FunctionsA Simulink 
 is a MEX function. A binary MEX function is a dynamic link library (Windows) or a shared object (UNIX) file. The file name is the MATLAB function name followed by the platform specific file extension returned by mexext(). MATLAB loads executable code from the file into memory and finds the address of the exported symbol mexFunction.\n
mexFunction takes the four arguments nlhs, plhs, nrhs, prhs. If nlhs is positive or zero, the call is from MATLAB, and the arguments describe the number and location of the inputs and outputs. If nlhs is negative, the call is from Simulink, one of the left-hand side arguments is a pointer to the SimStruct, and one of the right-hand side arguments is a flag telling which model function to run. The definition of mexFunction is in simulink.c, included at the bottom of S-Functions written in C. One step in building an Ada S-Function is to compile sl_ada_entry.c, which includes simstruc.c and simulink.c. The linker includes the resulting object file as well as objects compiled from Ada sources in the MEX files, and exports mexFunction.