Message Communication Interfaces
Within a platform environment, code generated from a Simulink® model can communicate with platform software or with other code generated from Simulink models by using message-based communication. Generate C++ component code for message-based communication with platform software. Generate C++ or C component code for message-based communication with other models.
Note
C code generation is not supported for models that connect the message port of a Simulink block or Stateflow chart to a top model root-level Inport or Outport block. For those modeling patterns, only C++ code generation is supported.
Generate C++ Messages to Communicate Data Between Simulink and an Operating System or Middleware
To generate C++ code that supports message communication between Simulink top models and external applications, use the Simulink Messages & Events Library Send and Receive blocks. Generating code from a top model to facilitate messages passed outside of the Simulink environment enables your modeled application to communicate in a distributed system that uses an external message protocol service, commonly referred to as an operating system or middleware (for example, DDS, ROS, SOMEIP, or POSIX messages).
Simulink top models pass messages by:
Top models contain message blocks to communicate outside the Simulink environment. If a top model contains a Send block directly connected to a root Outport block, the block converts its signals into messages and passes them outside the Simulink environment. If a top model contains a Receive block directly connected to a root Inport block, the block converts the received messages into signals.
The external message protocol manages the message communication according to its own standard, that is, policies that control capacity, order of delivery, and other quality of service (QoS) behavior.
To generate C++ messages to communicate between Simulink top models and an operating system or middleware, prepare your model, generate code, and integrate that code with your selected operating system or middleware.
Prepare Model
To set up your model so that it can pass messages with an operating system or middleware, configure the model as a top model that has at least one message block, either a Send block connected to a root Outport block or a Receive block connected to a root Inport block. The top model can then connect to your selected operating system or middleware through the message blocks:
Within a model, the message ports are connected as shown:
Generate Code
To generate C++ code from a model:
In the Apps gallery, click Embedded Coder.
In the Configuration Parameters dialog box, set these parameters:
In the Code Generation pane, set the Language to
C++
.In the Interface pane, set Code interface packaging to
C++ class
.In the Templates pane, select
Generate an example main program
.
Generate code. On the C++ Code tab, click Build.
View the generated code. On the C++ Code tab, click View Code.
Integrate Code
To integrate the generated C++ code from your model with your selected operating system or middleware use handwritten code to implement send and receive message classes and application code that uses those classes to pass messages. Specifically:
If you use your own main, create concrete subclasses from the generated abstract classes shown in
RecvData_<T>.h
andSendData<T>.h
. If you use the generated example main program, concrete subclasses are provided in the file.Implement the class functions
SendData
andRecvData
to call into your selected operating system or middleware to send and receive messages.Create an instance of your implemented send and receive message classes (send and receive objects).
Create an instance of the model class by using the instances of each message class (send and receive objects) as arguments in the model constructor.
Send and receive messages as required by your application. Manage the lifetime of the message queues.The queues must be in a state ready to accept messages prior to the first step of the model.
To integrate the generated code with a platform main program:
Open the generated example main program or create your own. If you use the generated example main program, the concrete subclasses
RecvData_real_T
andSendData_real_T
are in the file. If you create your own main, create concrete subclasses in your application code:To receive messages, manually write the implementation of the generated receive class. Implement the class function
RecvData
to call into your selected operating system or middleware to receive messages.An example implementation for POSIX is:
class mHMIHandlerRecvData_real_T: public RecvData_real_T { public: void RecvData(real_T* data, int32_T length, int32_T* status) { // Use POSIX API mq_receive to receive messages unsigned int priority = 1; *status = mq_receive(msgQueue, (char *)data, length, &priority); } };
Create a receive object.
static mHMIHandlerRecvData_real_T InMsgRecvData_arg;
To send messages, manually write the implementation of the generated send class. Implement the class function
SendData
to call into your selected operating system or middleware to send messages.An example implementation for POSIX is:
class mHMIHandlerSendData_real_T : public SendData_real_T { public: void SendData(const real_T* data, int32_T length, int32_T* status) { // Use the POSIX API mq_send to send messages unsigned int priority = 1; *status = mq_send(msgQueue, (char*)data, length, priority); } };
Create a send object.
static mHMIHandlerSendData_real_T OutMesgSendData_arg;
Create an instance of the model class by using your send and receive objects as arguments in the model constructor.
static mHMIHandler mHMI_Obj(InMsgRecvData_arg, OutMsgSendData_arg);
Send and receive messages as required by your application and maintain the lifetime of the message queue.
An example implementation for POSIX is:
int_T main(int_T argc, const char *argv[]) { // Unused arguments (void)(argc); (void)(argv); //Initialize model mHMI_obj.initialize(); // Open POSIX queue mqd_t msgQueue = mq_open("/PosixMQ_Example", O_RDONLY); if (msgQueue == -1) { printf("mq_open failed\n"); exit(1); } // Send and Receive messages while (rtmGetErrorStatus(mHMI_Obj.getRTM()) == (NULL)) { //perform application tasks here. rt_OneStep(); } // Close POSIX queue mq_close(msgQueue); // Terminate model mHMI_Obj.terminat(): return 0; }
For a more complex POSIX integration example, see Model Message-Based Communication Integrated with POSIX Message Queues
Considerations and Limitations
Handwritten code is the only supported integration technique.
You must select the model configuration parameter Generate an example main program. Applications that require a static main are not supported.
You cannot configure function prototype control (FPC) for a top model that has root message ports.
Generate C++ Messages to Communicate Data Between Simulink Components
To generate 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 or for ERT-based system target files by using Embedded Coder.
Messages are an effective communication technique for distributed and complex systems that you can model within Simulink.
How to Prepare Models in Simulink for Message-Based Communication
In Simulink, model message-based communication between model components:
Create a model that contains a Send block (referenced model).
Create a model that contains a Receive block (referenced model).
Create a model that has 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 generates in the top model above the message line. A queue, explicit or implicit, controls the message communication. You can use the generated queue or you can add a Queue block in the top model to explicitly specify communication parameters.
How Model Components Pass Messages and How the Code Implements the Behavior
Referenced models pass messages:
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.
In the generated C++ code, 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++ code implements message behavior:
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 to 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 to the top model.
C++ Code Generation Example
This example generates and examines C++ code from the model provided in Establish Message Send and Receive Interfaces Between Software Components.
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)
andSendComponentSendData(*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 functionsRecvData
andSendData
).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 to 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
orSendData
) 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.
Considerations and Limitations
C++ code support is available for GRT-based system target files by using the Simulink Coder app.
C++ code support is available for ERT-based system target files by using the Embedded Coder app.
To generate code, for top and referenced models, select the same language (C++) and the same system target file.
You cannot configure function prototype control (FPC) for a top model that has root message ports.
External models and variant models are not supported.
Software-in-the-loop (SIL) and processor-in-the-loop (PIL) simulations are not supported.
Generate C Messages to Communicate Data Between Simulink Components
To generate 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 or for ERT-based system target files by using Embedded Coder.
Messages are an effective communication technique for distributed and complex systems that you can model within Simulink.
How to Prepare Models in Simulink for Message-Based Communication
In Simulink, you can model message-based communication between model components:
Create a model that contains a Send block (referenced model).
Create a model that contains a Receive block (referenced model).
Create a model that has 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 generates in the top model above the message line. A queue, explicit or implicit, controls the message communication. You can use the generated queue or you can add a Queue block in the top model to explicitly specify communication parameters.
How Model Components Pass Messages and How the Code Implements the Behavior
Referenced models pass messages:
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.
In the generated C code, 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 code implements message behavior:
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 to 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 to the top model.
C Code Generation Example
This example generates and examines C code from the model provided in Establish Message Send and Receive Interfaces Between Software Components.
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 that have 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 fileSendData_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 that have 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 fileRecvData_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 to 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. 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.
Considerations and Limitations
C code support is available for GRT-based system target files by using the Simulink Coder app.
C code support is available for ERT-based system target files by using the Embedded Coder app.
To generate code, for top and referenced models, select the same language (C) and the same system target file.
You cannot configure function prototype control (FPC) for a top model that has root message ports.
External models and variant models are not supported.
Software-in-the-loop (SIL) and processor-in-the-loop (PIL) simulations are not supported.
C code generation is not supported for models that connect a message port of a Simulink block or a Stateflow chart to a top model root-level Inport or Outport block. For those modeling patterns, only C++ code generation is supported.