Main Content

Interact with C API Signal Code Throughout Execution

In this step of the example you write code that interacts with the generated C API signal code throughout execution of the generated code.

Open the model CapiSigsParams.

capiMdl = "CapiSigsParams";
open_system(capiMdl);

Integrate External Code in Generated Model Code

In this step of the example you integrate three external functions into the generated model code. These functions interact with the generated C API model code while it is running. These are the three functions, which are defined in the file CapiSigsParams_04.c:

  • initCapiFcn — The code in this function initializes the data structures used by your external code. This function is invoked during the initialization of the model execution.

  • realTimeCapiFcn — The code in this function prints the value of the signals every 10 steps. This function is invoked in each step of the model execution.

  • cleanCapiFcn — The code in this function cleans up memory used by your external code. This function is invoked when model execution terminates.

Add Initialization and Termination Functions to Model Code Execution

To add the invocation of initCapiFcn and cleanCapiFcn you specify this custom code information:

Specified Information

Custom Code Instruction

Where the functions is declared

Include header directive

Where the functions is defined

Source file path

When to invoke initCapiFcn

Function call to initCapiFcn in the model initialization code

When to invoke cleanCapiFcn

Function call to cleanCapiFcn in the model termination code

Store these custom code information instructions in variables.

includeHeaderDirective = '# include "CapiSigsParamsFiles/CapiSigsParamsDemo.h"';
srcFilePath = "CapiSigsParamsFiles/CapiSigsParams_04.c";
addInitCode = "initCapiFcn();";
addTerminateCode = "cleanCapiFcn();";

To add these code generation instructions:

  1. Open the Configuration Parameters dialog box.

  2. Navigate to the Code Generation > Custom Code pane.

  3. In the Custom code settings section, select the Code Information tab and enter the include header directive and the source file path in the Include headers and Source files boxes, respectively.

  4. Select the Additional source code tab and enter the function calls to the initCapiFcn and cleanCapiFcn in the Initialize code and Terminate code boxes, respectively.

  5. Click OK.

Configuration Parameters dialog box. The Code Generation > Custom Code pane is open. In the Code information tab of the Custom code settings section, the include header directive is specified in the Include headers box as '# include "CapiSigsParamsFiles/CapiSigsParamsDemo.h"'

Alternatively, you can specify these parameters programmatically by entering these commands in the Command Window:

set_param(capiMdl,CustomHeaderCode=includeHeaderDirective)
set_param(capiMdl,CustomSource=srcFilePath)
set_param(capiMdl,CustomInitializer=addInitCode)
set_param(capiMdl,CustomTerminator=addTerminateCode)

Add Step Function to Model Code Execution

One way to plug code into the model step function is by using a C Caller block. In the model canvas, add a C Caller block to the model and specify its function as realTimeCapiFcn.

Alternatively, use the capiSigsParamsHelper MATLAB® program to programmatically add the C Caller block.

capiSigsParamsHelper("cCaller")

CapiSigsParams model. The output signals of the Gain blocks are labeled on the model canvas as test points.

The function realTimeCapiFcn uses the C API interface to access the real-time values of model signals. Like the exploreCapiSignals function described in the previous step, this function gets the pointer to the signal array map and gets the signal names. Then the function:

  1. Gets the pointer to the real-time data address map. The pointer is a field of rtwCAPI_ModelMappingInfo, which is an inner structure in the main C API model map.

  2. Gets the data address indices from the signal map array.

  3. Uses the indices to reference into the data address map to get the pointers to the real-time value of the signals.

  4. Prints the signal names and their real-time values every 30th step of the model.

To view the definition of the function realTimeCapiFcn, examine the file CapiSigsParams_04.c.

/** realTimeCapiFcn **
* Uses the C API to send the signal values to the monitor.
*/
void realTimeCapiFcn()
{
  if(capiStage == 2)
  { /* The C API data structures are already terminated. */
    return;
  }

  int shouldPrint = !(capiStep%10);
  if(shouldPrint)
  {
    for(int idx=0 ; idx<sigCount ; idx++)
    {
      printf("step %0.3i: %s = %lf",capiStep,
                          capiSigArr[idx].signalName,
                                  *((double*)sigPtrs[idx]));
      if(idx < sigCount-1)
      {
        printf(" , ");
      }
    }
    printf(".\n");
    fflush(0);
    usleep(500000);
  }
  capiStep++;
}
/* End realTimeCapiFcn */

The figure shows the relationships of the data structures in the realTimeCapiFcn function.

Schematic representation of model and C API data structures, and their inter-relations. The main C API model map is shown as a field in the real-time model object. A pointer to the static C API map is shown as a field in the main map. A pointer to the signal array is shown as a field in Signals, which is an inner structure of the static map, and a pointer to the primitive type data address array is shown as a field in InstanceMap, which is an inner structure of the main map. Indices that reference entries #0 and #1 in the data address array are shown as fields in entries #0 and #1 in the signal array, respectively.

Add Mock Step Function to Model Simulation

In this example you do not simulate the model, but since you added the C Caller block you need to also specify header and source files also for the simulation. You cannot use the source file you specified for code generation, because it depends on the generated model code. Instead, for the simulation you specify the source file simMockSrc.c. This file contains an empty definition of the realTimeCapiFcn function. Use the mock header file, simMockSrc.h, to specify the include header directive for the simulation.

Store the include header directive and the path to the mock file in a variables.

mockIncludeDirective = '# include "CapiSigsParamsFiles/simMockSrc.h"';
mockFilePath = "CapiSigsParamsFiles/simMockSrc.c";

To add the simulation custom code instructions:

  1. Open the Configuration Parameters dialog box and navigate to the Simulation Target pane.

  2. In the Code Information tab, paste the include header directive and the path to the source file in the Include headers and Source files boxes respectively.

  3. Click OK.

Configuration Parameters dialog box. The Simulation Target pane is open. In the Code information tab of the Custom code settings section, the source file path is specified in the Source files box as CapiSigsParamsFiles/simMockSrc.c

Alternatively, you can specify these parameters programmatically by entering these commands in the Command Window:

set_param(capiMdl,SimCustomHeaderCode=mockIncludeDirective)
set_param(capiMdl,SimUserSources=mockFilePath)

Generate and Run Model Code

Use the slbuild command to generate code from your model. Use evalc to suppress the output of the slbuild command.

evalc("slbuild(capiMdl,GenerateCodeOnly=false)");

The code generator generates a standalone executable from the model. Use the system command to run this executable with the "-echo" input argument so that you can see the output of the model executable, with the printing from the exploreCapiModelElements function.

system(capiMdl,"-echo");
/bin/bash: line 1: CapiSigsParams: command not found

In the next step of the example, you configure the model to generate the C API elements also for model parameters, and you revise your external code to use the generate C API code to interact with both model signals and model parameters. To continue to the next step of the example, use this in the Command Window:

openExample("simulinkcoder/CapiSigsParams05Example")