To generate C++ or C code that supports message-based communication between model components in the Simulink environment, use the Simulink Messages & Events Library blocks Send and Receive. To customize the communication, use the Queue block (from the same library) to set parameters for capacity, sorting policy (LIFO, FIFO, and priority), and overwriting policy (behavior when the queue exceeds capacity). You can generate C code for GRT-based system target files by using Simulink Coder and generate C++ or C code for ERT-based system target files by using Embedded Coder.
Messages are an effective communication technique for distributed and complex systems that can be modeled within Simulink. To better understand the generated code support for message-based communication the following are explained:
How to prepare models in Simulink for message-based communication.
How model components pass messages and how the code implements this behavior.
How to generate and examine the C++ and C code from a given example model.
In Simulink, you can model message-based communication between model components using these steps:
Create a model that contains a Send block (referenced model).
Create a model that contains a Receive block (referenced model).
Create a model with two Model blocks (top model).
Set the first Model block to the model that contains the Send block (model from step 1).
Set the second Model block to the model that contains the Receive block (model from step 2).
When you run the model, a queue automatically generates in the top model above the message line. A queue, explicit or implicit, controls the message communication. You can use the automatically generated queue or you can add a Queue block in the top model to explicitly specify communication parameters.
To view an example of this design, see the model provided in Establish Message Send and Receive Interfaces Between Software Components (Simulink).
Conceptually, referenced models pass messages in the following way:
In the model that contains the Send block, the Send block converts signals into messages.
The top model that contains the queue manages messages according to parameters that define capacity, order of delivery, and other quality of service (QoS) metrics.
In the model that contains the Receive block, the Receive block converts messages back to signals.
The underlying architecture for the generated C++ and C code is very similar. The top model facilitates the connection between the send and receive referenced models by establishing a set interface that the referenced models can access independently of one another.
The generated C++ and C code implements message behavior in the following way:
A service is created at each model boundary. A service contains a reference to the top model and an entry point function, referred to as a service function, for referenced models to use to pass messages with the top model.
The top model initializes each service to create a connection to each referenced model.
The referenced models invoke service functions to pass messages with the top model.
Implementation details of these steps are shown in the generated code examples.
This example generates and examines C++ code from the model provided in Establish Message Send and Receive Interfaces Between Software Components (Simulink).
Generate C++ Code:
Open the model.
In the Apps gallery, click Embedded Coder.
For each model (top and both referenced models), in the Configuration Parameters dialog box, set these parameters:
In the Code Generation pane, set Language to
C++
.
In the Interface pane, set Code interface packaging to
C++ class
.
Save the model.
Generate code. On the C++ Code tab, click Build.
View the generated code. On the C++ Code tab, click View Code.
Examine C++ Code:
A service is created at each model boundary. In C++, services are represented as objects that hold an instance of the top model and a service function that referenced models invoke to pass messages.
To view the creation of the services, open the top model C++ file,
MessageSendReceiveDefaultBufferModel.cpp
. View the
constructor method.
The constructor methods, ReceiveComponentRecvData(*this)
and SendComponentSendData(*this)
, create the receive and send
service objects respectively by taking as an argument a reference to the instance
of the top model. Each service object saves a reference to the top model and
defines the message interface (the service functions RecvData
and SendData
).
To view the receive and send service classes, open the top model header file,
MessageSendReceiveDefaultBufferModel.h
, and view the
following section.
The top model initializes each service to create a connection to each referenced
model. To view the initialization, open the top model C++ file,
MessageSendReceiveDefaultBufferModel.cpp
. View the constructor
method.
The constructor method,
Receive_ComponentMDLOBJ0(get_ReceiveComponentRecvData())
, passes
a reference to the receive service to the receive referenced model. The constructor
method, Send_ComponentMDLOBJ1(get_SendComponentSendData())
, passes
a reference to the send service to the send referenced model.
The referenced models invoke service functions to pass messages with the top
model. In C++, referenced models invoke the top model (common ancestor, if in a
hierarchy) service functions to send or receive messages (specifically, a referenced
model invokes the abstract service method (RecvData
or
SendData
) from the interface created in step 2).The abstract
interface classes are emitted to a shared folder. The implementation of the service
functions in each service is defined in the top model C++ file.
To view the abstract interface class to send messages, open from the shared
folder the header file, SendData_real_T.h
.
To view the implementation of the service function to send messages, open the
top model C++ file,
MessageSendReceiveDefaultBufferModel.cpp
.
To view how the send referenced model invokes the service function, open its
C++ file, mSend.cpp
. In the step function, the model invokes
the service function to send messages to the top model and receives back a return
status.
To view the abstract interface class to receive messages, open from the shared
folder the header file, RecvData_real_T.h
.
To view the implementation of the service function to receive messages, open
top model C++ file,
MessageSendReceiveDefaultBufferModel.cpp
.
To view how the receive referenced model invokes the service function, open
its C++ file, mRecieve.cpp
. In the step function, the model
invokes the service function to receive messages and a status from the top
model.
This example generates and examines C code from the model provided in Establish Message Send and Receive Interfaces Between Software Components (Simulink).
Generate C Code:
Open the model.
In the Apps gallery, click Embedded Coder.
For each model (top and both referenced models), in the Configuration Parameters
dialog box, in the Code Generation pane, set Language to
C
and save the model.
Generate code. On the C Code tab, click Build.
View the generated code. On the C Code tab, click View Code.
Examine C Code:
A service is created at each model boundary. In C, referenced models represent services as DWork. The service provides a pointer to an instance of the top model and a service function that referenced models invoke to pass messages.
To view the service to send messages, open the send referenced model header
file, mSend.h
. View the DWork allocation.
To view the send message data type, if the data type is shareable (for
example, built-in data types, imported bus types, or exported bus types with a
specified data type) the information is located in a shared header file. If the
data type is not shareable the information is located the model header file,
mSend.h
. For this example, view the shareable data type by
opening the shared header file, SendData_real_T.h
.
To view the service to receive messages, open the receive referenced model
header file, mReceive.h
. View the DWork allocation.
To view the received messages data type, if the data type is shareable (for
example,built-in data types, imported bus types, or exported bus types with a
specified data type) the information is located in a shared header file. If the
data type is not shareable the information is located the model header file,
mReceive.h
. For this example, view the shareable data type by
opening the shared header file, RecvData_real_T.h
.
The top model initializes each service to create a connection to each referenced
model. In C, the top model initializes each referenced model DWork. To view the
initialization, open the top model C file,
MessageSendReceiveDefaultBufferModel.c
.
The referenced models invoke service functions to pass messages with the top model. In C, a referenced model invokes a service function by dereferencing the service function pointer and passing a pointer to the instance of the top model. You can view the prototypes of the service functions in the top model header file, and you can view the referenced model invocations of those service functions in the referenced model C files.
To view the prototype of the service function to send messages, open the top
model header file,
MessageSendReceiveDefaultBufferModel.h
.
To view the implementation of the service function to send messages, open the
top model C file,
MessageSendReceiveDefaultBufferModel.c
.
To view how the send referenced model invokes the service function, open the C
file for the model, mSend.c
. In the step function, the model
invokes the service to send instance data and a message to the top model and
receives back a return status.
To view the prototype of the service function to receive messages, open the
top model header file,
MessageSendReceiveDefaultBufferModel.h
.
To view the implementation of the service function to receive messages, open
the top model C file,
MessageSendReceiveDefaultBufferModel.c
.
To view how the receive referenced model invokes the service function, open
the C file for the model, mReceive.c
. In the step function, the
model invokes the service to receive a message payload and a return status.
C code support is available for GRT-based system target files by using the Simulink Coder App.
C and C++ code support is available for ERT-based system target files by using the Embedded Coder App.
To generate code, top and referenced models must have the same language (C++/C) and system target file selected.
Function prototype control (FPC) cannot be configured for a top model that has root message ports.
External models and variant models are not supported.
In simulation, SIL/PIL is not supported.