Main Content

Generate C Data Transfer Service Interface Code for Component Deployment

Since R2022b

This example shows how to generate calls to target platform data transfer service functions to exchange data between callable entry-point functions generated from a component model. The generated interface code must align with environment-specific service function prototypes and data communication methods.

In the example you:

  1. Represent a data transfer request in the top model.

  2. Configure the code generator to apply the default data transfer code interface.

  3. Generate and inspect the interface code.

  4. Configure the data transfer code interface for during-execution data access.

  5. Regenerate and reinspect the interface code.

Represent Data Transfer Request in Top Model

Open example component model ComponentDeploymentFcn.

open_system('ComponentDeploymentFcn');

component-deployment-fcn-model.png

The signal line that connects the output port of the Integrator function to the input port of the Accumulator function represents a data transfer. The integrator function calls the data transfer service to send data to the accumulator function. The accumulator function calls the data transfer service to receive the data from the integrator function. For more information about modeling data transfers, see cgsl_0409: Data transfer for component deployment.

Configure Data Transfer Code Interface

The example model is linked to shared Embedded Coder Dictionary file ComponentDeploymentCoderDictionary.sldd, which defines a service code interface configuration. That configuration defines two data transfer service interfaces, one for outside-execution data access (the default) and one for during-execution data access. Both interfaces specify naming rules set_$X$N and get_$X$N, where $X is the name of the service function and $N is the name of the signal that represents the data transfer.

Configure the model such that the code generator applies the coder dictionary default interface for data transfers.

  1. Open the Embedded Coder app.

  2. Select Code Interface > Component Interface.

  3. In the Code Mappings editor, click the Data Transfers tab.

  4. Select the row for Data Transfer.

  5. From the menu in the Data Transfer Service column of the selected row, select Dictionary default: DataTransferOutsideExe. As the name indicates, the default interface is configured to use outside-execution data communication.

Generate and Inspect Interface Code

Generate code from the example model. The code generator creates the folder ComponentDeploymentFcn_ert_rtw in the current working folder and places source code files in that folder. The generated code is in two primary files: header file ComponentDeploymentFcn.h and source code file ComponentDeploymentFcn.c. Model data and entry-point functions are accessible to a caller by including the header file in target environment software.

The code generator also produces an interface header file, which by default the code generator names services.h. This file includes declarations for platform service interface functions called by the component code.

To inspect the generated code, use the generated Code Interface Report or, in the Embedded Coder app, use the Code view. The report is helpful for verifying that the generated interface code aligns with code interface requirements.

For a data transfer service interface, the report provides:

  • Receiver and sender function prototypes

  • Data communication method used

  • Generated callable entry-point functions that call the service functions

Header File

The header file ComponentDeploymentFcn.h includes interface header file services.h, defines an instance of the real-time model data structure, and declares structures and callable entry-point functions for data and function interface elements represented in the model.

This code fragment shows lines of code in the header file that are relevant to data transfer requests: the inclusion of services.h and the generated entry-point functions that call data transfer service functions.

#include "services.h"
.
.
.
extern void CD_initialize(void);
extern void CD_accumulator(void);
extern void CD_integrator(void);

Source Code File

When the model is configured for the code generator to produce interface code that uses outside-execution data communication, entry-point functions in the generated source code file ComponentDeploymentFcn.c call these target platform data transfer service functions:

  • get_CD_accumulator_DataTransfer

  • set_CD_integrator_DataTransfer

  • set_ModelInitialize_DataTransfer

When a service interface uses the outside-execution data communication method, calls to the service functions take no arguments.

void CD_accumulator(void)
{
  const real_T *tmpIrvIRead;
  int32_T i;
  tmpIrvIRead = get_CD_accumulator_DataTransfer();
  for (i = 0; i < 10; i++) {
    CD_measured.delay[i] += tmpIrvIRead[i];
    (getref_CD_accumulator_OutBus_y())[i] = CD_tunable.k * CD_measured.delay[i];
  }
}

void CD_integrator(void)
{
  real_T tmp;
  real_T *tmp_0;
  int32_T i;
  uint32_T Integrator_ELAPS_T;
  tmp_0 = set_CD_integrator_DataTransfer();
.
.
.
  for (i = 0; i < 10; i++) {
    if ((int32_T)rtDWork.DiscreteTimeIntegrator_SYSTEM_E == 0) {
      CD_measured.dti[i] += tmp * rtDWork.DiscreteTimeIntegrator_PREV_U[i];
    }

    rtDWork.discreteTimeIntegrator_PREV_U[i] = (get_CD_integrator_InBus_u())[i];
}    

  rtDWork.DiscreteTimeIntegrator_SYSTEM_E = 0U;
  memcpy(&tmp_0[0], &CD_measured.dti[0], (uint32_T)(10U * sizeof(real_T)));
}

void CD_initialize(void)
{
  {
    real_T *tmp;
    int32_T i;
    tmp = set_ModelInitialize_DataTransfer();
    for (i = 0; i < 10; i++) {
      tmp[i] = 5.0;
    }
.
.
.
}

The accumulator function calls the data transfer service function get_CD_accumulator_DataTransfer to read an input value transferred from the integrator function. The accumulator function uses the input to compute the accumulated value.

The integrator function calls the data transfer service function set_CD_integrator_DataTransfer to transfer an integrated output value to the accumulator function. The initialize function calls the service function set_ModelInitialize_DataTransfer to initialize state data that is read from nonvolatile memory. When a service interface uses outside-execution data communication, the generated code calls these data transfer service functions before the for loop. The target platform data transfer service:

  • Gives access to the buffer for the entry-point functions to populate.

  • Reads the buffer after the entry-point function executes.

  • Uses the buffered value for the next task iteration.

Services Header File

The services header file services.h declares prototypes for calling services that run as platform software in a target environment. This code fragment shows the prototype declarations for calling data transfer service functions.

/* data transfer services */
const real_T * get_CD_accumulator_DataTransfer(void);
real_T * set_CD_integrator_DataTransfer(void);
real_T * set_ModelInitialize_DataTransfer(void);

For an interface that uses the outside-execution data communication method, the code generator expects the target environment to provide a buffer for data communication. Because the target environment software creates and manages access to the buffer, the data transfer service functions take no arguments.

The function names reflect the naming rules defined for the data transfer service interface in the linked Embedded Coder Dictionary. The naming rules get_$X$N and set_$X$N instruct the code generator to $X with the name of the calling entry-point function and $N with the name of the source or destination signal port for the data transfer.

Configure Data Transfer Code Interface for During-Execution Data Access

Configure the example model such that the code generator applies the coder dictionary interface for during-execution data transfers.

  1. If the Embedded Coder app is not open, open it and select Code Interface > Component Interface.

  2. In the Code Mappings editor, click the Data Transfers tab.

  3. Select the row for Data Transfer.

  4. From the menu in the Data Transfer Service column of the selected row, select service interface DataTransferDuringExe.

  5. Save the configuration change by saving the model.

Regenerate and Reinspect Interface Code

Regenerate code from the example model.

The generated code shown in the following sections assumes that you have configured the inports, outports, data transfers, and the timer service for the integrator function with a service interface that applies the during-execution data communication method.

Header File

The lines of code relevant to the data transfer code interface in header file ComponentDeploymentFcn.h are the same as for the outside-execution data transfer interface.

#include "services.h"
.
.
.
extern void CD_initialize(void);
extern void CD_terminate(void);
extern void CD_accumulator(void);
extern void CD_integrator(void);

Source Code File

When the model is configured for the code generator to produce interface code that uses during-execution data communication, entry-point functions in the generated source code file ComponentDeploymentFcn.c call these target platform data transfer service functions:

  • get_CD_accumulator_DataTransfer

  • set_CD_integrator_DataTransfer

  • set_ModelInitialize_DataTransfer

When a service interface uses the during-execution data communication method, the call to service function get_CD_accumulator_DataTransfer takes a pointer to a buffer as an argument. Calls to service functions set_CD_integrator_DataTransfer and set_ModelInitialize_DataTransfer take a constant buffer as an argument.

void CD_accumulator(void)
{
  real_T OutBus_y[10];
  int32_T i;
  get_CD_accumulator_DataTransfer(OutBus_y);
  for (i = 0; i < 10; i++) {
    CD_measured.delay[i] += OutBus_y[i];
    OutBus_y[i] = CD_tunable.k * CD_measured.delay[i];
  }

  set_CD_accumulator_output(&OutBus_y[0]);
}

void CD_integrator(void)
{
  real_T tmp[10];
  real_T tmp_0;
  int32_T i;
  uint32_T Integrator_ELAPS_T;
  tmp_0 = set_CD_integrator_DataTransfer();
.
.
.
  for (i = 0; i < 10; i++) {
    if ((int32_T)rtDWork.DiscreteTimeIntegrator_SYSTEM_E == 0) {
      CD_measured.dti[i] += tmp_0 * rtDWork.DiscreteTimeIntegrator_PREV_U[i];
    }

    rtDWork.discreteTimeIntegrator_PREV_U[i] = tmp[i];
  }    

  rtDWork.DiscreteTimeIntegrator_SYSTEM_E = 0U;
  set_CD_integrator_DataTransfer(CD_measured.dti);
}

void CD_initialize(void)
{
  {
    real_T tmp[10];
    int32_T i;
    get_CD_initialize_InBus_NVM(&CD_measured.delay[0]);
    for (i = 0; i < 10; i++) {
      tmp[i] = 5.0;
    }

    set_ModelInitialize_DataTransfer(tmp);
.
.
.
  }
}

When a service interface uses the during-execution data communcation method, the generated code calls the same data transfer service as when you use the outside-execution mentod. The target platform service can execute while generated entry-point function execute. For each of the interface functions, the code generator produces a data buffer (OutBus_y, CD_measured.dti, and tmp). The entry-point function code populates the buffer inside the for loop.

The accumulator function calls the data transfer service function get_CD_accumulator_DataTransfer to read an input value transferred from the integrator function to data buffer OutBus_y. The accumulator function uses the input to compute the accumulated value.

The integrator function calls the data transfer service function set_CD_integrator_DataTransfer to transfer the integrated output value stored in data buffer CD_measured_dti to the accumulator function. The initialize function calls service function set_ModelInitialize_DataTransfer to initialize state data that is read from nonvolatile memory data buffer tmp. When using outside-execution data communication, the generated code calls these data transfer service functions after the for loop. Thus, the target platform data transfer services called once during execution of each entry-point function.

Services Header File

This code fragment shows the prototype declarations for calling data transfer service functions when when the interface uses during-execution data communication.

/* data transfer services */
void get_CD_accumulator_DataTransfer(real_T *aValPtr);
void set_CD_integrator_DataTransfer(const real_T aVal[10]);
void set_ModelInitialize_DataTransfer(const real_T aVal[10]);

The generated data transfer service function interfaces each take an argument. Function get_CD_accumulator_DataTransfer takes a pointer to a buffer as an argument. Functions set_CD_integrator_DataTransfer and set_ModelInitialize_DataTransfer take a constant buffer as an argument.

Related Examples

More About