Contenuto principale

Programmatically Customize C Functions Generated from Global Simulink Functions

In the generated model code, each Simulink function corresponds to one of the generated functions. The return value and input arguments of the generated function represent the Argument Inport and Argument Outport blocks of the Simulink function, and the function body corresponds to the Simulink function logic.

A global Simulink® function is a Simulink Function block with the Function visibility parameter of its Trigger block specified as global. Global Simulink functions are callable from any function generated from the model, regardless of the hierarchical relationship between the functions.

This example shows how to programmatically customize the generated function name, return value, and input arguments.

Load Model and Explore Global Simulink Function Block

Load the model.

sfModel = "SimFuncs";
load_system(sfModel)

Verify that globalSimFunc is a global Simulink Function block by getting the value of the Function visibility parameter of its Trigger block:

globalSfTrig = "SimFuncs/globalSimFunc/g_func";
get_param(globalSfTrig,"FunctionVisibility")
ans = 
'global'

Prepare to Customize Generated Function

To customize the function generated from the global Simulink function programmatically, you use the code mapping object associated with the model. Get a handle to the code mapping object of the model and store it in a variable.

codeMapObj = coder.mapping.api.get(sfModel);

Customize Generated Function Name

You specify the naming rule to use for generating the function name as a combination of valid C language characters and macros defined in Identifier Format Tokens. In this example, use the $N macro in the naming rule so the generated function name contains the Simulink function name, g_func. Specify the naming rule as my_$N.

Use the find function with the code mappings object to find the identifier of the Simulink function:

funcNames = find(codeMapObj,"Functions");
globalSfCodeMappingID = funcNames(contains(funcNames,"g_func"))
globalSfCodeMappingID = 
"SimulinkFunction:g_func"

Use the function setFunction with the code mappings object and the identifier to specify the function name:

setFunction(codeMapObj,globalSfCodeMappingID,FunctionName="my_$N")

Use the slbuild function in the Command Window to generate code from the model. Use the evalc function to suppress the output of the slbuild function.

evalc("slbuild(sfModel)");

Store the path to the generated source file in srcFile, then use the coder.example.extractLines function to see the customized name in the generated file.

srcFile = "SimFuncs_ert_rtw/SimFuncs.c";
coder.example.extractLines(srcFile,"g_func(","{");
void my_g_func(real_T rtu_g_in1, real_T rtu_g_in2, real_T *rty_g_out1, real_T
               *rty_g_out2)

The function name adheres to the naming rule you specified.

Customize Function Arguments

The generated function uses its input arguments and its return value to represent the Argument Inport and Argument Outport blocks of the Simulink function. You can:

  • Optionally designate one of the Argument Outport blocks of the Simulink function to become the return value of the generated function. Each of the remaining Argument Outport blocks corresponds to one pointer input argument.

  • Specify the type qualifier of each argument that corresponds to a Simulink function Argument Inport block — passing the argument by value, or by reference as a pointer input argument.

  • Customize argument order.

  • Customize argument identifiers.

To customize the arguments, use the function setFunction this way:

setFunction(codeMapObj,globalSfCodeMappingID,Arguments=arg_spec)

Here, codeMapObj is the code mappings object of the model, globalSfCodeMappingID is the identifier of the Simulink function as defined in the code mappings of the model, and arg_spec is a variable with the expression that specifies how the Argument Inport and Argument Outport blocks of the Simulink function are represented and arranged in the prototype of the generated function.

The generic structure of the argument specifications expression is "return_value_outport = (arg1, arg2, ... , argN)".

The part before the parenthesis is optional. Include it to designate the Simulink function Argument Outport block return_value_outport as the return value of the generated function. The rest of the Argument Outport blocks of the Simulink function become pointer input arguments in the generated function. If you do not designate an Argument Outport block as the return value, all Argument Outport blocks of the Simulink function become pointer input arguments.

Each of the Argument Inport and Argument Outport blocks of the Simulink function, except for the Argument Outport block designated as the return value of the generated function (if there is one), corresponds to one element in the comma separated list arg1, arg2, ... , argN. The element includes the name of the Simulink function Argument Inport or Argument Outport block, and in some cases, additional specifications:

  • An element that corresponds to an Argument Outport block of the Simulink function must be preceded by an asterisk (*) to indicate that the generated argument is a pointer.

  • An element that corresponds to an Argument Inport block of the Simulink function can optionally be preceded by const*. Use this prefix to specify that the generated argument is a pointer to a constant. If you do not include the const* prefix, the code generator attempts to generate the argument without a pointer declarator (passed by value). But, in certain conditions the code generator still generates the argument as a pointer to constant.

  • The default name for each generated argument is the identifier of the corresponding Simulink function Argument Inport or Argument Outport block. Optionally, you can specify a custom naming rule to use for the identifier of the corresponding argument. To do this, add a space after the port identifier followed by the naming rule. The naming rule must be a combination of valid C language characters and macros defined in Identifier Format Tokens. In the example, we use the macros $I and $N in the naming rules of argument identifiers. The macro $N is replaced by the identifier of the port in the Simulink function. The macro $I is replaced by u for Argument Inport blocks of the Simulink function, by y for Argument Outport blocks of the Simulink function, and by uy for combined arguments. Using combined arguments is demonstrated in the Use Combined Inports and Outports section of the example. You cannot customize the identifier of the return value.

  • The order of the arguments in the generated function is the order of the elements in the comma separated list arg1, arg2, ... , argN.

In this example, store these argument specifications in the variable arg_spec:

arg_spec = "g_out2 = (const* g_in2 rule1_$I_$N , *g_out1 rule2_$I_$N , g_in1)";

Here is a breakdown of the specifications used to customize the arguments of the generated function:

There is no naming rule for the third argument. Its identifier is the identifier of the Argument Inport block itself, g_in1.

Use the function setFunction with arg_spec:

setFunction(codeMapObj,globalSfCodeMappingID,Arguments=arg_spec)

Use the set_param function to update the model.

set_param(sfModel,SimulationCommand="Update")

Rebuild model code.

evalc("slbuild(sfModel)");

Use the coder.example.extractLines function to see the generated function in the generated source code file.

coder.example.extractLines(srcFile,"g_func(","}",true,true);
real_T my_g_func(const real_T *rule1_u_g_in2, real_T *rule2_y_g_out1, real_T
                 g_in1)
{
  real_T rty_g_out2_0;

  /* Gain: '<S1>/gGain5' incorporates:
   *  Gain: '<S1>/gGain1'
   *  Gain: '<S1>/gGain2'
   *  Gain: '<S1>/gGain3'
   *  Gain: '<S1>/gGain4'
   *  SignalConversion generated from: '<S1>/g_in1'
   *  Sum: '<S1>/gAdd'
   */
  rty_g_out2_0 = (22.0 * g_in1 * 6.0 + 3.0 * *rule1_u_g_in2 * 10.0) * 2003.0;

  /* SignalConversion generated from: '<S1>/g_out1' incorporates:
   *  Gain: '<S1>/FlipSign'
   */
  *rule2_y_g_out1 = -rty_g_out2_0;
  return rty_g_out2_0;
}

In the generated code:

  • The argument order, qualifiers, and identifiers adhere to your specifications.

  • During function execution, the return value is stored in the temporary variable rty_g_out2_0, which corresponds to the Argument Outport block g_out2.

Use Combined Argument Inport and Argument Outport Blocks

You can customize the generated function to have combined arguments, corresponding each to one Argument Inport block and one Argument Outport block of the Simulink function. A combined argument is passed by pointer and is used in the generated function for both input and output. To use combined arguments, specify the same identifier for both the Argument Inport block and the Argument Outport block in the Simulink Function block. In the example, update the Simulink function prototype with the argument g_in_out as both the first Argument Inport block and the first Argument Outport block of the Simulink function.

Store the new Simulink function prototype in the variable inOutPrototype, and store the paths to the Simulink function and to the Simulink function caller in the variables globalSf and globalSfCaller, respectively.

inOutPrototype = "[g_in_out,g_out2] = g_func(g_in_out,g_in2)";
globalSf = "SimFuncs/globalSimFunc";
globalSfCaller = "SimFuncs/globalSimFuncCaller";

Use the set_param function to update the Simulink function and its caller with the new prototype.

set_param(globalSf,FunctionPrototype=inOutPrototype)
set_param(globalSfCaller,FunctionPrototype=inOutPrototype)

Use the set_param function to update the model.

set_param(sfModel,SimulationCommand="Update")

Update arg_spec to conform to the new Simulink function prototype:

arg_spec = "void (* g_in_out gArg_$I_$N , g_in2 gArg_$I_$N , *g_out2 gArg_$I_$N)";

Use the function setFunction again, with the updated argument specifications:

setFunction(codeMapObj,globalSfCodeMappingID,Arguments=arg_spec)

Generate code from the model again:

evalc("slbuild(sfModel)");

Use the coder.example.extractLines function to see the new definition of the generated function.

coder.example.extractLines(srcFile,"g_func(","}");
void my_g_func(real_T *gArg_uy_g_in_out, real_T gArg_u_g_in2, real_T
               *gArg_y_g_out2)
{
  real_T rtb_gGain5;

  /* Gain: '<S1>/gGain5' incorporates:
   *  Gain: '<S1>/gGain1'
   *  Gain: '<S1>/gGain2'
   *  Gain: '<S1>/gGain3'
   *  Gain: '<S1>/gGain4'
   *  SignalConversion generated from: '<S1>/g_in2'
   *  Sum: '<S1>/gAdd'
   */
  rtb_gGain5 = (22.0 * *gArg_uy_g_in_out * 6.0 + 3.0 * gArg_u_g_in2 * 10.0) *
    2003.0;

  /* SignalConversion generated from: '<S1>/g_in_out~' incorporates:
   *  Gain: '<S1>/FlipSign'
   */
  *gArg_uy_g_in_out = -rtb_gGain5;

  /* SignalConversion generated from: '<S1>/g_out2' */
  *gArg_y_g_out2 = rtb_gGain5;

In the generated code:

  • The macro $I is replaced by uy for generating the combined argument identifier.

  • The argument gArg_uy_g_in_out is used for both input and output in the function body. Its value is used in the calculation and is being updated.

See Also

| | | | |

Topics