Main Content

Use C Caller Block with Conditional Execution

This example shows how to use a C Caller block with conditional execution. The example model contains two C Caller blocks whose outputs are input branches into a Switch block. Each C Caller block calls one of the custom C code functions sort_ascend() and sort_descend(). Only one of the values from the input branches is passed to the output side of the Switch block. A C Function block with the same settings can also be used in place of a C Caller block to call these custom code functions.

This example illustrates the following concepts:

  • Calling custom C code from a Simulink® block in a conditional execution context.

  • Configuring deterministic functions by function in custom code.

Examine the Model

This model calls custom code through a C Caller block that is connected to an input branch of a Switch block.

open_system('slexCCallerConditional');

Generate Code

The custom code functions in this model have not been identified as deterministic functions. When code is generated from the model, both C functions are executed during simulation and in the generated code, even though the Switch block requires the output of only one of the functions.

slbuild(bdroot);
cfile = fullfile('slexCCallerConditional_grt_rtw','slexCCallerConditional.c');
coder.example.extractLines(cfile,'/* Model step', '/* Matfile logging', 1, 0);
### Starting build procedure for: slexCCallerConditional
### Successful completion of build procedure for: slexCCallerConditional

Build Summary

Top model targets:

Model                   Build Reason                                         Status                        Build Duration
=========================================================================================================================
slexCCallerConditional  Information cache folder or artifacts were missing.  Code generated and compiled.  0h 0m 21.841s 

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 24.348s

/* Model step function */
void slexCCallerConditional_step(void)
{
  real_T rtb_CCallerascend[6];
  real_T rtb_CCallerdescend[6];
  int32_T i;

  /* CCaller: '<Root>/C Caller (ascend)' incorporates:
   *  Inport: '<Root>/In2'
   */
  for (i = 0; i < 6; i++) {
    rtb_CCallerascend[i] = slexCCallerConditional_U.In2[i];
  }

  sort_ascend(&rtb_CCallerascend[0], 6);

  /* End of CCaller: '<Root>/C Caller (ascend)' */

  /* CCaller: '<Root>/C Caller (descend)' incorporates:
   *  Inport: '<Root>/In2'
   */
  for (i = 0; i < 6; i++) {
    rtb_CCallerdescend[i] = slexCCallerConditional_U.In2[i];
  }

  sort_descend(&rtb_CCallerdescend[0], 6);

  /* End of CCaller: '<Root>/C Caller (descend)' */
  for (i = 0; i < 6; i++) {
    /* Switch: '<Root>/Switch' incorporates:
     *  Inport: '<Root>/In1'
     */
    if (slexCCallerConditional_U.In1 > 0.0) {
      /* Outport: '<Root>/Out3' */
      slexCCallerConditional_Y.Out3[i] = rtb_CCallerascend[i];
    } else {
      /* Outport: '<Root>/Out3' */
      slexCCallerConditional_Y.Out3[i] = rtb_CCallerdescend[i];
    }

    /* End of Switch: '<Root>/Switch' */
  }

Specify Custom Code Deterministic Functions

Open the Configuration Parameters dialog box.

In the Simulation Target pane, set Deterministic functions to By Function. Click Specify by function and add the functions sort_ascend and sort_descend to the list. This action tells the model that the specified custom code functions have deterministic behavior, that is, the same input values to the functions always give the same outputs. If a function is set to be deterministic, it does not need to be called if it is in the input branch corresponding to a false value of the Switch block.

configset.highlightParameter(bdroot,'DefaultCustomCodeDeterministicFunctions');
set_param(bdroot,'DefaultCustomCodeDeterministicFunctions','ByFunction');
set_param(bdroot,'CustomCodeDeterministicFunctions','sort_ascend,sort_descend');

Generate Code Again

Now that you have specified the deterministic functions, the generated code is more efficient because only the C Caller block in the true branch of the Switch block is executed. The same efficiency applies when you simulate the model in Simulink.

slbuild(bdroot);
cfile = fullfile('slexCCallerConditional_grt_rtw','slexCCallerConditional.c');
coder.example.extractLines(cfile,'/* Model step', '/* Matfile logging', 1, 0);
close_system(bdroot, 0);
### Starting build procedure for: slexCCallerConditional
### Successful completion of build procedure for: slexCCallerConditional

Build Summary

Top model targets:

Model                   Build Reason                     Status                        Build Duration
=====================================================================================================
slexCCallerConditional  Generated code was out of date.  Code generated and compiled.  0h 0m 14.177s 

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 15.201s

/* Model step function */
void slexCCallerConditional_step(void)
{
  real_T rtb_CCallerascend[6];
  int32_T i;

  /* Switch: '<Root>/Switch' incorporates:
   *  Inport: '<Root>/In1'
   */
  if (slexCCallerConditional_U.In1 > 0.0) {
    /* CCaller: '<Root>/C Caller (ascend)' incorporates:
     *  Inport: '<Root>/In2'
     */
    for (i = 0; i < 6; i++) {
      rtb_CCallerascend[i] = slexCCallerConditional_U.In2[i];
    }

    sort_ascend(&rtb_CCallerascend[0], 6);

    /* End of CCaller: '<Root>/C Caller (ascend)' */
  } else {
    /* CCaller: '<Root>/C Caller (descend)' incorporates:
     *  Inport: '<Root>/In2'
     */
    for (i = 0; i < 6; i++) {
      rtb_CCallerascend[i] = slexCCallerConditional_U.In2[i];
    }

    sort_descend(&rtb_CCallerascend[0], 6);

    /* End of CCaller: '<Root>/C Caller (descend)' */
  }

  /* End of Switch: '<Root>/Switch' */

  /* Outport: '<Root>/Out3' */
  for (i = 0; i < 6; i++) {
    slexCCallerConditional_Y.Out3[i] = rtb_CCallerascend[i];
  }

  /* End of Outport: '<Root>/Out3' */

See Also

| | |