Messages
The MARTe messaging mechanism allows components to exchange information and commands based on the Objects addresses (source and destination) in the ObjectRegistryDatabase.
Messages enable to change the behaviour of an application based only on configuration data, i.e. without requiring any code recompilation.
Messages also provide a generic interface between MARTe components and any components and protocols that live outside a MARTe application. This allows, for instance, to replace an external component without changing the internal message protocol.
This interface is typically used for non real-time activities, such as configuration and state management. In particular, messages are the main technology behind the StateMachine

The main actors are the Message and the MessageI components. The former defines the payload, the sender and the destination of the message. The latter is the interface that allows to receive messages.
Message
The Message requires the definition of the following parameters:
Sender: the Object that is sending the message;
Destination: the Object that will receive the message;
Function: a string which identifies the scope of the action to be performed in the Destination object;
IsReply: true if this message is a reply to a previous message;
ExpectsReply: true if a reply is expected from the Destination component.

Given that the Message is also a ReferenceContainer the payload is defined by the References that are inserted into the container.
MessageI
In order to be able to receive messages a component shall inherit from MessageI and shall register one or more filters that will be responsible for deciding if a given message is to be accepted.
Filters shall inherit from MessageFilter and can be either permanent or temporary. A temporary filter will be removed from the MessageI after accepting the first message.
class MessageFilterEx1: public MARTe::Object, public MARTe::MessageFilter {
...
//Permanent filter => MessageFilter(true)
MessageFilterEx1 () : MARTe::Object(), MARTe::MessageFilter(true) {
}
virtual MARTe::ErrorManagement::ErrorType ConsumeMessage(MARTe::ReferenceT<MARTe::Message> &messageToTest) {
//Check if this filter is appropriate to handle the message
}
class MessageEx1: public MARTe::Object, public MARTe::MessageI {
...
MessageEx1 () : MARTe::Object(), MARTe::MessageI() {
filter = ReferenceT<MessageFilterEx1>(GlobalObjectsDatabase::Instance()->GetStandardHeap());
filter->SetOwner(this);
//Install the filter
ErrorManagement::ErrorType ret = MessageI::InstallMessageFilter(filter);
}


A Message is sent by calling the function MessageI::SendMessage
and may be called in any context and from any component (even if it does not inherit from Object).
...
ErrorManagement::ErrorType err = MessageI::SendMessage(msg, this);
...
Replies
The reply to a message can be either direct or indirect. In both cases the same Message instance is used for the reply. The replier is allowed to change the payload as needed.
In the case of a direct reply, the sender waits (polls) for the Message instance to change from IsReply() == false
to IsReply() == true
. As such, the message sender does not have to inherit from MessageI
. The only requirement is that it inherits from Object.

Original message instance …

… is changed to update the Destination
field to the original sender (note that IsReply() is now true).

...
//This function will poll and wait for msg->IsReply() to be changed to true
err = MessageI::SendMessageAndWaitReply(msg, this);
...
Conversely, indirect replies require the sender to inherit from MessageI
. The reason is that indirect replies are treated as a normal message, but sent back from the replier to the sender.


Indirect replies can be used, for instance, to implement asynchronous message exchanging, allowing, for example, to wait for the reply in the context of a different thread (e.g. by using a QueuedReplyMessageCatcherFilter).
...
//This function will automatically register a ReplyMessageCatcherMessageFilter filter and poll for the message to arrive. It is functionally equivalent
err = SendMessageAndWaitIndirectReply(msg, this);
...
if (messageToTest->ExpectsIndirectReply()) {
messageToTest->SetAsReply(true);
//Indirect reply... resend the message
err = MessageI::SendMessage(messageToTest, this);
}
The type of reply is encoded in the Message configuration using the Mode
field.
+Msg1 = {
Class = Message
Destination = "MsgRec1"
Function = "Function0"
Mode = "ExpectsIndirectReply"
}
Filters
As explained above, the messages are trapped by the MessageFilter components.
The framework offers a set of standard filters that are ready to be used:
Filter |
Description |
---|---|
Allows to manage (purge and load) the ObjectRegistryDatabase and thus change the configuration of the application in runtime (see example below). |
|
Enables the call of remote Object functions using messages (see below). |
|
Waits for a given reply to arrive. Typically used with indirect messages. |
|
Listens for messages in the context of a different thread and puts the messages in a queue (shall be used with a QueuedMessageI). |
|
Similar to the ReplyMessageCatcherMessageFilter but waits for the message in the context of a different thread. |
Note
The message sender does not know what filter will be used to consume the message. As such, it cannot make any assumptions on how the message will be handled (e.g. threading context, existence of a queue, …).
Note
The type of filter does not depend on the fact of the message being sent with a direct or an indirect reply.
Remote function calls
One of the most powerful features of this interface is the possibility of registering functions that can be called using messages.
The prototype of the function to be registered shall be one of (where T is any of the basic types, including StreamString:vcisdoxygencl:):
ErrorManagement::ErrorType (*) ();
ErrorManagement::ErrorType (*) (T param1);
ErrorManagement::ErrorType (*) (T param1, T param2);
ErrorManagement::ErrorType (*) (T param1, T param2, T param3);
ErrorManagement::ErrorType (*) (T param1, T param2, T param3, T param4);
Note
Constantness and in/output declaration of the parameter will be respected. In particular, output parameters will be updated, with the values changed during the function execution, in the message reply.
The methods are registered with the macro CLASS_METHOD_REGISTER
(requires including CLASSMETHODREGISTER.h
). The class registering functions shall also inherit from MessageI and register a RegisteredMethodsMessageFilter:
class MessageEx1: public MARTe::Object, public MARTe::MessageI {
...
MessageEx1 () : MARTe::Object(), MARTe::MessageI() {
...
filter = ReferenceT<RegisteredMethodsMessageFilter>(GlobalObjectsDatabase::Instance()->GetStandardHeap());
filter->SetDestination(this);
...
}
...
MARTe::ErrorManagement::ErrorType Function0 () {
REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "Function0 called.");
return MARTe::ErrorManagement::NoError;
}
MARTe::ErrorManagement::ErrorType Function1 (MARTe::uint32 a, MARTe::float32 b) {
REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "Received %u %f.", a, b);
return MARTe::ErrorManagement::NoError;
}
...
CLASS_REGISTER(MessageEx1, "")
CLASS_METHOD_REGISTER(MessageEx1, Function0)
CLASS_METHOD_REGISTER(MessageEx1, Function1)
Note
The following functions prototypes can also be registered but, as of today, are not reacheable using the messaging mechanism.
ErrorManagement::ErrorType (*) (StreamI &stream);
ErrorManagement::ErrorType (*) (StructuredDataI &config);
ErrorManagement::ErrorType (*) (ReferenceContainer &container);
Parameters are encoded in a Message by adding a ConfigurationDatabase
node, named Parameters
, containing up to four elements, named param1
, param2
, param3
and param4
, with the parameter values.
+Msg1 = {
Class = Message
Destination = "MsgRec1"
Function = "Function1"
Mode = "ExpectsIndirectReply"
+Parameters = {
Class = ConfigurationDatabase
param1 = 2
param2 = 3.14
}
}
The name of the function to call is encoded in the Function
message parameter.
Examples
Direct messages - no reply
The following is an example of direct message sending with no reply.
1/**
2 * @file MessageExample1.cpp
3 * @brief Source file for class MessageExample1
4 * @date 08/04/2018
5 * @author Andre' Neto
6 *
7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
8 * the Development of Fusion Energy ('Fusion for Energy').
9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
11 * You may not use this work except in compliance with the Licence.
12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
13 *
14 * @warning Unless required by applicable law or agreed to in writing,
15 * software distributed under the Licence is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17 * or implied. See the Licence permissions and limitations under the Licence.
18
19 * @details This source file contains the definition of all the methods for
20 * the class MessageExample1 (public, protected, and private). Be aware that some
21 * methods, such as those inline could be defined on the header file, instead.
22 */
23
24#define DLL_API
25
26/*---------------------------------------------------------------------------*/
27/* Standard header includes */
28/*---------------------------------------------------------------------------*/
29
30/*---------------------------------------------------------------------------*/
31/* Project header includes */
32/*---------------------------------------------------------------------------*/
33#include "AdvancedErrorManagement.h"
34#include "ConfigurationDatabase.h"
35#include "ErrorLoggerExample.h"
36#include "MessageI.h"
37#include "MessageFilter.h"
38#include "Object.h"
39#include "ObjectRegistryDatabase.h"
40#include "Sleep.h"
41#include "StandardParser.h"
42
43/*---------------------------------------------------------------------------*/
44/* Static definitions */
45/*---------------------------------------------------------------------------*/
46namespace MARTe2Tutorial {
47
48/**
49 * @brief Message filter for the MessageEx1 below.
50 */
51class MessageFilterEx1: public MARTe::Object, public MARTe::MessageFilter {
52public:
53 CLASS_REGISTER_DECLARATION()
54
55 /**
56 * @brief NOOP.
57 */
58MessageFilterEx1 () : MARTe::Object(), MARTe::MessageFilter(true) {
59 using namespace MARTe;
60 }
61
62 virtual void Purge(MARTe::ReferenceContainer &purgeList) {
63 owner = MARTe::Reference();
64 }
65
66 virtual ~MessageFilterEx1 () {
67 if (GetName() != NULL) {
68 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
69 "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
70 }
71 }
72
73 void SetOwner(MARTe::Reference ownerIn) {
74 owner = ownerIn;
75 }
76
77 virtual MARTe::ErrorManagement::ErrorType ConsumeMessage(MARTe::ReferenceT<MARTe::Message> &messageToTest);
78
79private:
80 MARTe::Reference owner;
81
82};
83CLASS_REGISTER(MessageFilterEx1, "")
84
85/**
86 * @brief A MARTe::Object class that will receive messages.
87 */
88class MessageEx1: public MARTe::Object, public MARTe::MessageI {
89public:
90 CLASS_REGISTER_DECLARATION()
91
92 /**
93 * @brief Install the message filter.
94 */
95MessageEx1 () : MARTe::Object(), MARTe::MessageI() {
96 using namespace MARTe;
97 filter = ReferenceT<MessageFilterEx1>(GlobalObjectsDatabase::Instance()->GetStandardHeap());
98 filter->SetOwner(this);
99 MessageI::InstallMessageFilter(filter);
100 messageReceived = false;
101 }
102
103 virtual ~MessageEx1 () {
104 if (GetName() != NULL) {
105 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
106 "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
107 }
108 }
109
110 virtual void Purge(MARTe::ReferenceContainer &purgeList) {
111 filter->SetOwner(MARTe::Reference());
112 RemoveMessageFilter(filter);
113 }
114
115 /**
116 * @brief Print the message contents in the screen.
117 */
118 MARTe::ErrorManagement::ErrorType CheckMessage(MARTe::ReferenceT<MARTe::Message> &messageToTest) {
119 using namespace MARTe;
120 const Object *senderObj = messageToTest->GetSender();
121 CCString sender = senderObj ? senderObj->GetName() : "anonymous";
122 CCString destination = messageToTest->GetDestination();
123 CCString function = messageToTest->GetFunction();
124 bool expectsReply = messageToTest->ExpectsReply();
125 bool expectsIndirectReply = messageToTest->ExpectsIndirectReply();
126 bool isReply = messageToTest->IsReply();
127 REPORT_ERROR(MARTe::ErrorManagement::Information, "Received message from %s to %s with function %s "
128 "(expectsReply? %d expectsIndirectReply? %d isReply? %d", sender.GetList(), destination.GetList(),
129 function.GetList(), expectsReply, expectsIndirectReply, isReply);
130
131 messageReceived = true;
132 return ErrorManagement::NoError;
133 }
134
135 bool messageReceived;
136private:
137 MARTe::ReferenceT<MessageFilterEx1> filter;
138};
139
140CLASS_REGISTER(MessageEx1, "")
141
142//Delegate to the owner the handling of the message (but could be handled by the filter itself as well).
143MARTe::ErrorManagement::ErrorType MessageFilterEx1::ConsumeMessage(MARTe::ReferenceT<MARTe::Message> &messageToTest) {
144 MARTe::ReferenceT<MessageEx1> ownerT = owner;
145 MARTe::ErrorManagement::ErrorType err;
146 err.fatalError = !owner.IsValid();
147 if (err.ErrorsCleared()) {
148 err = ownerT->CheckMessage(messageToTest);
149 }
150 return err;
151}
152
153/**
154 * @brief A MARTe::ReferenceContainer class that will send any messages inserted into it. Note that it does not inherit from MessageI.
155 */
156class MessageEx2: public MARTe::ReferenceContainer {
157public:
158 CLASS_REGISTER_DECLARATION()
159
160 /**
161 * @brief NOOP.
162 */
163MessageEx2 () : MARTe::ReferenceContainer() {
164 }
165
166 virtual ~MessageEx2 () {
167 if (GetName() != NULL) {
168 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
169 "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
170 }
171 }
172
173 void SendMessages() {
174 using namespace MARTe;
175 uint32 numberOfMessages = Size();
176 uint32 i;
177 for (i=0u; i<numberOfMessages; i++) {
178 ReferenceT<Message> msg = Get(i);
179 if (msg.IsValid()) {
180 ErrorManagement::ErrorType err = MessageI::SendMessage(msg, this);
181 REPORT_ERROR(err, "Message %s sent", msg->GetName());
182 }
183 }
184 }
185
186};
187
188CLASS_REGISTER(MessageEx2, "")
189
190}
191/*---------------------------------------------------------------------------*/
192/* Method definitions */
193/*---------------------------------------------------------------------------*/
194
195int main(int argc, char **argv) {
196 using namespace MARTe;
197 using namespace MARTe2Tutorial;
198 SetErrorProcessFunction(&ErrorProcessExampleFunction);
199
200 StreamString configurationCfg = ""
201 "+MsgRec1 = {\n"
202 " Class = MessageEx1\n"
203 "}\n"
204 "+MsgRec2 = {\n"
205 " Class = MessageEx1\n"
206 "}\n"
207 "+MsgRec3 = {\n"
208 " Class = MessageEx1\n"
209 "}\n"
210 "+MsgSender1= {\n"
211 " Class = MessageEx2\n"
212 " +Msg1 = {\n"
213 " Class = Message\n"
214 " Destination = MsgRec3"
215 " Function = \"AFunction\""
216 " }"
217 " +Msg2 = {\n"
218 " Class = Message\n"
219 " Destination = MsgRec2"
220 " Function = \"BFunction\""
221 " }"
222 " +Msg3 = {\n"
223 " Class = Message\n"
224 " Destination = MsgRec1"
225 " Function = \"CFunction\""
226 " }"
227 "}";
228
229 REPORT_ERROR_STATIC(ErrorManagement::Information, "Loading CFG:\n%s", configurationCfg.Buffer());
230 ConfigurationDatabase cdb;
231 StreamString err;
232 //Force the string to be seeked to the beginning.
233 configurationCfg.Seek(0LLU);
234 StandardParser parser(configurationCfg, cdb, &err);
235 bool ok = parser.Parse();
236 if (ok) {
237 //After parsing the tree is pointing at the last leaf
238 cdb.MoveToRoot();
239 ok = ObjectRegistryDatabase::Instance()->Initialise(cdb);
240 }
241 else {
242 StreamString errPrint;
243 errPrint.Printf("Failed to parse %s", err.Buffer());
244 REPORT_ERROR_STATIC(ErrorManagement::ParametersError, errPrint.Buffer());
245 }
246
247 if (ok) {
248 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully loaded the configuration file");
249 }
250
251 ReferenceT<MessageEx1> msgRec1 = ObjectRegistryDatabase::Instance()->Find("MsgRec1");
252 ReferenceT<MessageEx1> msgRec2 = ObjectRegistryDatabase::Instance()->Find("MsgRec2");
253 ReferenceT<MessageEx1> msgRec3 = ObjectRegistryDatabase::Instance()->Find("MsgRec3");
254 ReferenceT<MessageEx2> msgSender1 = ObjectRegistryDatabase::Instance()->Find("MsgSender1");
255
256 if ((msgSender1.IsValid()) && (msgRec1.IsValid()) && (msgRec2.IsValid()) && (msgRec3.IsValid())) {
257 msgSender1->SendMessages();
258 while (!msgRec1->messageReceived) {
259 Sleep::MSec(100);
260 }
261 while (!msgRec2->messageReceived) {
262 Sleep::MSec(100);
263 }
264 while (!msgRec3->messageReceived) {
265 Sleep::MSec(100);
266 }
267 }
268 //Purge all the Objects!
269 MARTe::ObjectRegistryDatabase::Instance()->Purge();
270 return 0;
271}
Direct messages - reply
Another example of a direct message sending, but with reply.
1/**
2 * @file MessageExample2.cpp
3 * @brief Source file for class MessageExample2
4 * @date 17/04/2018
5 * @author Andre' Neto
6 *
7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
8 * the Development of Fusion Energy ('Fusion for Energy').
9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
11 * You may not use this work except in compliance with the Licence.
12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
13 *
14 * @warning Unless required by applicable law or agreed to in writing,
15 * software distributed under the Licence is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17 * or implied. See the Licence permissions and limitations under the Licence.
18
19 * @details This source file contains the definition of all the methods for
20 * the class MessageExample2 (public, protected, and private). Be aware that some
21 * methods, such as those inline could be defined on the header file, instead.
22 */
23
24#define DLL_API
25
26/*---------------------------------------------------------------------------*/
27/* Standard header includes */
28/*---------------------------------------------------------------------------*/
29
30/*---------------------------------------------------------------------------*/
31/* Project header includes */
32/*---------------------------------------------------------------------------*/
33#include "AdvancedErrorManagement.h"
34#include "ConfigurationDatabase.h"
35#include "ErrorLoggerExample.h"
36#include "MessageI.h"
37#include "MessageFilter.h"
38#include "Object.h"
39#include "ObjectRegistryDatabase.h"
40#include "Sleep.h"
41#include "StandardParser.h"
42
43/*---------------------------------------------------------------------------*/
44/* Static definitions */
45/*---------------------------------------------------------------------------*/
46namespace MARTe2Tutorial {
47
48/**
49 * @brief Message filter for the MessageEx1 below (which replies to the message sent).
50 */
51class MessageFilterEx1: public MARTe::Object, public MARTe::MessageFilter {
52public:
53 CLASS_REGISTER_DECLARATION()
54
55 /**
56 * @brief NOOP.
57 */
58MessageFilterEx1 () : MARTe::Object(), MARTe::MessageFilter(true) {
59 using namespace MARTe;
60 }
61
62 virtual void Purge(MARTe::ReferenceContainer &purgeList) {
63 owner = MARTe::Reference();
64 }
65
66 virtual ~MessageFilterEx1 () {
67 if (GetName() != NULL) {
68 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
69 "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
70 }
71 }
72
73 void SetOwner(MARTe::Reference ownerIn) {
74 owner = ownerIn;
75 }
76
77 virtual MARTe::ErrorManagement::ErrorType ConsumeMessage(MARTe::ReferenceT<MARTe::Message> &messageToTest);
78
79private:
80 MARTe::Reference owner;
81
82};
83CLASS_REGISTER(MessageFilterEx1, "")
84
85/**
86 * @brief A MARTe::Object class that will receive and reply to messages.
87 */
88class MessageEx1: public MARTe::Object, public MARTe::MessageI {
89public:
90 CLASS_REGISTER_DECLARATION()
91
92 /**
93 * @brief Install the message filter.
94 */
95MessageEx1 () : MARTe::Object(), MARTe::MessageI() {
96 using namespace MARTe;
97 filter = ReferenceT<MessageFilterEx1>(GlobalObjectsDatabase::Instance()->GetStandardHeap());
98 filter->SetOwner(this);
99 MessageI::InstallMessageFilter(filter);
100 messageReceived = false;
101 }
102
103 virtual ~MessageEx1 () {
104 if (GetName() != NULL) {
105 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
106 "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
107 }
108 }
109
110 virtual void Purge(MARTe::ReferenceContainer &purgeList) {
111 filter->SetOwner(MARTe::Reference());
112 RemoveMessageFilter(filter);
113 }
114
115 /**
116 * @brief Print the message contents in the screen.
117 */
118 MARTe::ErrorManagement::ErrorType CheckMessage(MARTe::ReferenceT<MARTe::Message> &messageToTest) {
119 using namespace MARTe;
120 const Object *senderObj = messageToTest->GetSender();
121 CCString sender = senderObj ? senderObj->GetName() : "anonymous";
122 CCString destination = messageToTest->GetDestination();
123 CCString function = messageToTest->GetFunction();
124 bool expectsReply = messageToTest->ExpectsReply();
125 bool expectsIndirectReply = messageToTest->ExpectsIndirectReply();
126 bool isReply = messageToTest->IsReply();
127 REPORT_ERROR(MARTe::ErrorManagement::Information, "Received message from %s to %s with function %s "
128 "(expectsReply? %d expectsIndirectReply? %d isReply? %d", sender.GetList(), destination.GetList(),
129 function.GetList(), expectsReply, expectsIndirectReply, isReply);
130
131 messageReceived = true;
132 return ErrorManagement::NoError;
133 }
134
135 bool messageReceived;
136private:
137 MARTe::ReferenceT<MessageFilterEx1> filter;
138};
139
140CLASS_REGISTER(MessageEx1, "")
141
142//Delegate to the owner the handling of the message (but could be handled by the filter itself as well).
143MARTe::ErrorManagement::ErrorType MessageFilterEx1::ConsumeMessage(MARTe::ReferenceT<MARTe::Message> &messageToTest) {
144 using namespace MARTe;
145 ReferenceT<MessageEx1> ownerT = owner;
146 ErrorManagement::ErrorType err;
147 err.fatalError = !owner.IsValid();
148 if (err.ErrorsCleared()) {
149 err = ownerT->CheckMessage(messageToTest);
150 }
151 //Mark the message as a (direct) reply
152 if (err.ErrorsCleared()) {
153 messageToTest->SetAsReply(true);
154 //And insert an (example) object into
155 ReferenceT<Object> example = ReferenceT<Object>(GlobalObjectsDatabase::Instance()->GetStandardHeap());
156 example->SetName("REPLY");
157 messageToTest->Insert(example);
158 }
159 return err;
160}
161
162/**
163 * @brief A MARTe::ReferenceContainer class that will send any messages inserted into it.
164 * Note that it does not inherit from MessageI.
165 */
166class MessageEx2: public MARTe::ReferenceContainer {
167public:
168 CLASS_REGISTER_DECLARATION()
169
170 /**
171 * @brief NOOP.
172 */
173MessageEx2 () : MARTe::ReferenceContainer() {
174 replyReceived = false;
175 }
176
177 virtual ~MessageEx2 () {
178 if (GetName() != NULL) {
179 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
180 "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
181 }
182 }
183
184 void SendMessages() {
185 using namespace MARTe;
186 uint32 numberOfMessages = Size();
187 uint32 i;
188 for (i=0u; i<numberOfMessages; i++) {
189 ReferenceT<Message> msg = Get(i);
190 ErrorManagement::ErrorType err;
191 err.fatalError = !msg.IsValid();
192 if (err.ErrorsCleared()) {
193 err = MessageI::SendMessageAndWaitReply(msg, this);
194 REPORT_ERROR(err, "Message %s sent", msg->GetName());
195 }
196 if (err.ErrorsCleared()) {
197 if (msg->IsReply()) {
198 REPORT_ERROR(err, "Message %s is now a reply as expected", msg->GetName());
199 }
200 if (msg->Size() > 0) {
201 Reference ref = msg->Get(0);
202 REPORT_ERROR(err, "Message %s contains an object in the reply with name %s", msg->GetName(), ref->GetName());
203 }
204 }
205 }
206 replyReceived = true;
207 }
208
209 bool replyReceived;
210};
211
212CLASS_REGISTER(MessageEx2, "")
213
214}
215/*---------------------------------------------------------------------------*/
216/* Method definitions */
217/*---------------------------------------------------------------------------*/
218
219int main(int argc, char **argv) {
220 using namespace MARTe;
221 using namespace MARTe2Tutorial;
222 SetErrorProcessFunction(&ErrorProcessExampleFunction);
223
224 StreamString configurationCfg = ""
225 "+MsgRec1 = {\n"
226 " Class = MessageEx1\n"
227 "}\n"
228 "+MsgRec2 = {\n"
229 " Class = MessageEx1\n"
230 "}\n"
231 "+MsgRec3 = {\n"
232 " Class = MessageEx1\n"
233 "}\n"
234 "+MsgSender1= {\n"
235 " Class = MessageEx2\n"
236 " +Msg1 = {\n"
237 " Class = Message\n"
238 " Destination = MsgRec3"
239 " Function = \"AFunction\""
240 " }"
241 " +Msg2 = {\n"
242 " Class = Message\n"
243 " Destination = MsgRec2"
244 " Function = \"BFunction\""
245 " }"
246 " +Msg3 = {\n"
247 " Class = Message\n"
248 " Destination = MsgRec1"
249 " Function = \"CFunction\""
250 " }"
251 "}";
252
253 REPORT_ERROR_STATIC(ErrorManagement::Information, "Loading CFG:\n%s", configurationCfg.Buffer());
254 ConfigurationDatabase cdb;
255 StreamString err;
256 //Force the string to be seeked to the beginning.
257 configurationCfg.Seek(0LLU);
258 StandardParser parser(configurationCfg, cdb, &err);
259 bool ok = parser.Parse();
260 if (ok) {
261 //After parsing the tree is pointing at the last leaf
262 cdb.MoveToRoot();
263 ok = ObjectRegistryDatabase::Instance()->Initialise(cdb);
264 }
265 else {
266 StreamString errPrint;
267 errPrint.Printf("Failed to parse %s", err.Buffer());
268 REPORT_ERROR_STATIC(ErrorManagement::ParametersError, errPrint.Buffer());
269 }
270
271 if (ok) {
272 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully loaded the configuration file");
273 }
274
275 ReferenceT<MessageEx1> msgRec1 = ObjectRegistryDatabase::Instance()->Find("MsgRec1");
276 ReferenceT<MessageEx1> msgRec2 = ObjectRegistryDatabase::Instance()->Find("MsgRec2");
277 ReferenceT<MessageEx1> msgRec3 = ObjectRegistryDatabase::Instance()->Find("MsgRec3");
278 ReferenceT<MessageEx2> msgSender1 = ObjectRegistryDatabase::Instance()->Find("MsgSender1");
279
280 if ((msgSender1.IsValid()) && (msgRec1.IsValid()) && (msgRec2.IsValid()) && (msgRec3.IsValid())) {
281 msgSender1->SendMessages();
282 while (!msgRec1->messageReceived) {
283 Sleep::MSec(100);
284 }
285 while (!msgRec2->messageReceived) {
286 Sleep::MSec(100);
287 }
288 while (!msgRec3->messageReceived) {
289 Sleep::MSec(100);
290 }
291 while (!msgSender1->replyReceived) {
292 Sleep::MSec(100);
293 }
294 }
295 //Purge all the Objects!
296 MARTe::ObjectRegistryDatabase::Instance()->Purge();
297 return 0;
298}
Indirect messages - reply
An example of an indirect message sending with reply.
1/**
2 * @file MessageExample3.cpp
3 * @brief Source file for class MessageExample3
4 * @date 17/04/2018
5 * @author Andre' Neto
6 *
7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
8 * the Development of Fusion Energy ('Fusion for Energy').
9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
11 * You may not use this work except in compliance with the Licence.
12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
13 *
14 * @warning Unless required by applicable law or agreed to in writing,
15 * software distributed under the Licence is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17 * or implied. See the Licence permissions and limitations under the Licence.
18
19 * @details This source file contains the definition of all the methods for
20 * the class MessageExample3 (public, protected, and private). Be aware that some
21 * methods, such as those inline could be defined on the header file, instead.
22 */
23
24#define DLL_API
25
26/*---------------------------------------------------------------------------*/
27/* Standard header includes */
28/*---------------------------------------------------------------------------*/
29
30/*---------------------------------------------------------------------------*/
31/* Project header includes */
32/*---------------------------------------------------------------------------*/
33#include "AdvancedErrorManagement.h"
34#include "ConfigurationDatabase.h"
35#include "ErrorLoggerExample.h"
36#include "MessageI.h"
37#include "MessageFilter.h"
38#include "Object.h"
39#include "ObjectRegistryDatabase.h"
40#include "ReplyMessageCatcherMessageFilter.h"
41#include "Sleep.h"
42#include "StandardParser.h"
43
44/*---------------------------------------------------------------------------*/
45/* Static definitions */
46/*---------------------------------------------------------------------------*/
47namespace MARTe2Tutorial {
48
49/**
50 * @brief Message filter for the MessageEx1 below (which replies to the message sent).
51 */
52class MessageFilterEx1: public MARTe::Object, public MARTe::MessageFilter {
53public:
54 CLASS_REGISTER_DECLARATION()
55
56 /**
57 * @brief NOOP.
58 */
59MessageFilterEx1 () : MARTe::Object(), MARTe::MessageFilter(true) {
60 using namespace MARTe;
61 }
62
63 virtual void Purge(MARTe::ReferenceContainer &purgeList) {
64 owner = MARTe::Reference();
65 }
66
67 virtual ~MessageFilterEx1 () {
68 if (GetName() != NULL) {
69 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
70 "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
71 }
72 }
73
74 void SetOwner(MARTe::Reference ownerIn) {
75 owner = ownerIn;
76 }
77
78 virtual MARTe::ErrorManagement::ErrorType ConsumeMessage(MARTe::ReferenceT<MARTe::Message> &messageToTest);
79
80private:
81 MARTe::Reference owner;
82
83};
84CLASS_REGISTER(MessageFilterEx1, "")
85
86/**
87 * @brief A MARTe::Object class that will receive and reply to messages.
88 */
89class MessageEx1: public MARTe::Object, public MARTe::MessageI {
90public:
91 CLASS_REGISTER_DECLARATION()
92
93 /**
94 * @brief Install the message filter.
95 */
96MessageEx1 () : MARTe::Object(), MARTe::MessageI() {
97 using namespace MARTe;
98 filter = ReferenceT<MessageFilterEx1>(GlobalObjectsDatabase::Instance()->GetStandardHeap());
99 filter->SetOwner(this);
100 MessageI::InstallMessageFilter(filter);
101 messageReceived = false;
102 }
103
104 virtual ~MessageEx1 () {
105 if (GetName() != NULL) {
106 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
107 "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
108 }
109 }
110
111 virtual void Purge(MARTe::ReferenceContainer &purgeList) {
112 filter->SetOwner(MARTe::Reference());
113 RemoveMessageFilter(filter);
114 }
115
116 /**
117 * @brief Print the message contents in the screen.
118 */
119 MARTe::ErrorManagement::ErrorType CheckMessage(MARTe::ReferenceT<MARTe::Message> &messageToTest) {
120 using namespace MARTe;
121 const Object *senderObj = messageToTest->GetSender();
122 CCString sender = senderObj ? senderObj->GetName() : "anonymous";
123 CCString destination = messageToTest->GetDestination();
124 CCString function = messageToTest->GetFunction();
125 bool expectsReply = messageToTest->ExpectsReply();
126 bool expectsIndirectReply = messageToTest->ExpectsIndirectReply();
127 bool isReply = messageToTest->IsReply();
128 REPORT_ERROR(MARTe::ErrorManagement::Information, "Received message from %s to %s with function %s "
129 "(expectsReply? %d expectsIndirectReply? %d isReply? %d", sender.GetList(), destination.GetList(),
130 function.GetList(), expectsReply, expectsIndirectReply, isReply);
131
132 messageReceived = true;
133 return ErrorManagement::NoError;
134 }
135
136 bool messageReceived;
137private:
138 MARTe::ReferenceT<MessageFilterEx1> filter;
139};
140
141CLASS_REGISTER(MessageEx1, "")
142
143//Delegate to the owner the handling of the message (but could be handled by the filter itself as well).
144MARTe::ErrorManagement::ErrorType MessageFilterEx1::ConsumeMessage(MARTe::ReferenceT<MARTe::Message> &messageToTest) {
145 using namespace MARTe;
146 ReferenceT<MessageEx1> ownerT = owner;
147 ErrorManagement::ErrorType err;
148 err.fatalError = !owner.IsValid();
149 if (err.ErrorsCleared()) {
150 err = ownerT->CheckMessage(messageToTest);
151 }
152 //Mark the message as a (direct) reply
153 if (err.ErrorsCleared()) {
154 messageToTest->SetAsReply(true);
155 //And insert an (example) object into
156 ReferenceT<Object> example = ReferenceT<Object>(GlobalObjectsDatabase::Instance()->GetStandardHeap());
157 example->SetName("REPLY");
158 messageToTest->Insert(example);
159 if (messageToTest->ExpectsIndirectReply()) {
160 //Indirect reply... resend the message
161 err = MessageI::SendMessage(messageToTest, this);
162 }
163 }
164 return err;
165}
166
167/**
168 * @brief A MARTe::Object class that will send indirect reply messages and waits for the reply.
169 * Note that the method SendMessageAndWaitIndirectReply will automatically register a ReplyMessageCatcherMessageFilter filter
170 */
171class MessageEx2: public MARTe::ReferenceContainer, public MARTe::MessageI {
172public:
173 CLASS_REGISTER_DECLARATION()
174
175 /**
176 * @brief NOOP
177 */
178 MessageEx2 () : MARTe::ReferenceContainer(), MARTe::MessageI() {
179 using namespace MARTe;
180 replyReceived = false;
181 }
182
183 virtual ~MessageEx2 () {
184 if (GetName() != NULL) {
185 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
186 "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
187 }
188 }
189
190 void SendMessages() {
191 using namespace MARTe;
192 uint32 numberOfMessages = Size();
193 uint32 i;
194 for (i=0u; i<numberOfMessages; i++) {
195 ReferenceT<Message> msg = Get(i);
196 ErrorManagement::ErrorType err;
197 err.fatalError = !msg.IsValid();
198 if (err.ErrorsCleared()) {
199 if (!msg->ExpectsIndirectReply()) {
200 msg->SetExpectsIndirectReply(true);
201 }
202 err = SendMessageAndWaitIndirectReply(msg);
203 REPORT_ERROR(err, "Message %s sent", msg->GetName());
204 }
205 if (err.ErrorsCleared()) {
206 if (msg->IsReply()) {
207 REPORT_ERROR(err, "Message %s is now a reply as expected", msg->GetName());
208 }
209 if (msg->Size() > 0) {
210 Reference ref = msg->Get(0);
211 REPORT_ERROR(err, "Message %s contains an object in the reply with name %s", msg->GetName(), ref->GetName());
212 }
213 }
214 }
215 replyReceived = true;
216 }
217
218 bool replyReceived;
219};
220
221CLASS_REGISTER(MessageEx2, "")
222
223}
224/*---------------------------------------------------------------------------*/
225/* Method definitions */
226/*---------------------------------------------------------------------------*/
227
228int main(int argc, char **argv) {
229 using namespace MARTe;
230 using namespace MARTe2Tutorial;
231 SetErrorProcessFunction(&ErrorProcessExampleFunction);
232
233 StreamString configurationCfg = ""
234 "+MsgRec1 = {\n"
235 " Class = MessageEx1\n"
236 "}\n"
237 "+MsgRec2 = {\n"
238 " Class = MessageEx1\n"
239 "}\n"
240 "+MsgRec3 = {\n"
241 " Class = MessageEx1\n"
242 "}\n"
243 "+MsgSender1= {\n"
244 " Class = MessageEx2\n"
245 " +Msg1 = {\n"
246 " Class = Message\n"
247 " Destination = MsgRec3"
248 " Function = \"AFunction\""
249 " Mode = \"ExpectsIndirectReply\""
250 " }"
251 " +Msg2 = {\n"
252 " Class = Message\n"
253 " Destination = MsgRec2"
254 " Function = \"BFunction\""
255 " Mode = \"ExpectsIndirectReply\""
256 " }"
257 " +Msg3 = {\n"
258 " Class = Message\n"
259 " Destination = MsgRec1"
260 " Function = \"CFunction\""
261 " Mode = \"ExpectsIndirectReply\""
262 " }"
263 "}";
264
265 REPORT_ERROR_STATIC(ErrorManagement::Information, "Loading CFG:\n%s", configurationCfg.Buffer());
266 ConfigurationDatabase cdb;
267 StreamString err;
268 //Force the string to be seeked to the beginning.
269 configurationCfg.Seek(0LLU);
270 StandardParser parser(configurationCfg, cdb, &err);
271 bool ok = parser.Parse();
272 if (ok) {
273 //After parsing the tree is pointing at the last leaf
274 cdb.MoveToRoot();
275 ok = ObjectRegistryDatabase::Instance()->Initialise(cdb);
276 }
277 else {
278 StreamString errPrint;
279 errPrint.Printf("Failed to parse %s", err.Buffer());
280 REPORT_ERROR_STATIC(ErrorManagement::ParametersError, errPrint.Buffer());
281 }
282
283 if (ok) {
284 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully loaded the configuration file");
285 }
286
287 ReferenceT<MessageEx1> msgRec1 = ObjectRegistryDatabase::Instance()->Find("MsgRec1");
288 ReferenceT<MessageEx1> msgRec2 = ObjectRegistryDatabase::Instance()->Find("MsgRec2");
289 ReferenceT<MessageEx1> msgRec3 = ObjectRegistryDatabase::Instance()->Find("MsgRec3");
290 ReferenceT<MessageEx2> msgSender1 = ObjectRegistryDatabase::Instance()->Find("MsgSender1");
291
292 if ((msgSender1.IsValid()) && (msgRec1.IsValid()) && (msgRec2.IsValid()) && (msgRec3.IsValid())) {
293 msgSender1->SendMessages();
294 while (!msgRec1->messageReceived) {
295 Sleep::MSec(100);
296 }
297 while (!msgRec2->messageReceived) {
298 Sleep::MSec(100);
299 }
300 while (!msgRec3->messageReceived) {
301 Sleep::MSec(100);
302 }
303 while (!msgSender1->replyReceived) {
304 Sleep::MSec(100);
305 }
306 }
307 //Purge all the Objects!
308 MARTe::ObjectRegistryDatabase::Instance()->Purge();
309 return 0;
310}
Queued messages
The following is an example of indirect messages handled in the context of a queue and of a different thread. The replies are also handled in the context of a different thread.
1/**
2 * @file MessageExample4.cpp
3 * @brief Source file for class MessageExample4
4 * @date 17/04/2018
5 * @author Andre' Neto
6 *
7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
8 * the Development of Fusion Energy ('Fusion for Energy').
9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
11 * You may not use this work except in compliance with the Licence.
12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
13 *
14 * @warning Unless required by applicable law or agreed to in writing,
15 * software distributed under the Licence is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17 * or implied. See the Licence permissions and limitations under the Licence.
18
19 * @details This source file contains the definition of all the methods for
20 * the class MessageExample4 (public, protected, and private). Be aware that some
21 * methods, such as those inline could be defined on the header file, instead.
22 */
23
24#define DLL_API
25
26/*---------------------------------------------------------------------------*/
27/* Standard header includes */
28/*---------------------------------------------------------------------------*/
29
30/*---------------------------------------------------------------------------*/
31/* Project header includes */
32/*---------------------------------------------------------------------------*/
33#include "AdvancedErrorManagement.h"
34#include "ConfigurationDatabase.h"
35#include "ErrorLoggerExample.h"
36#include "MessageI.h"
37#include "MessageFilter.h"
38#include "Object.h"
39#include "ObjectRegistryDatabase.h"
40#include "QueuedMessageI.h"
41#include "QueuedReplyMessageCatcherFilter.h"
42#include "Sleep.h"
43#include "StandardParser.h"
44
45/*---------------------------------------------------------------------------*/
46/* Static definitions */
47/*---------------------------------------------------------------------------*/
48namespace MARTe2Tutorial {
49
50/**
51 * @brief Message filter for the MessageEx1 below (which replies to the message sent).
52 */
53class MessageFilterEx1: public MARTe::Object, public MARTe::MessageFilter {
54public:
55 CLASS_REGISTER_DECLARATION()
56
57 /**
58 * @brief NOOP.
59 */
60 MessageFilterEx1 () : MARTe::Object(), MARTe::MessageFilter(true) {
61 using namespace MARTe;
62 }
63
64 virtual void Purge(MARTe::ReferenceContainer &purgeList) {
65 owner = MARTe::Reference();
66 }
67
68 virtual ~MessageFilterEx1 () {
69 if (GetName() != NULL) {
70 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
71 "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
72 }
73 }
74
75 void SetOwner(MARTe::Reference ownerIn) {
76 owner = ownerIn;
77 }
78
79 virtual MARTe::ErrorManagement::ErrorType ConsumeMessage(MARTe::ReferenceT<MARTe::Message> &messageToTest);
80
81private:
82 MARTe::Reference owner;
83
84};
85CLASS_REGISTER(MessageFilterEx1, "")
86
87/**
88 * @brief A MARTe::Object class that will receive and reply to messages.
89 */
90class MessageEx1: public MARTe::Object, public MARTe::QueuedMessageI {
91public:
92 CLASS_REGISTER_DECLARATION()
93
94 /**
95 * @brief Install the message filter.
96 */
97MessageEx1 () : MARTe::Object(), MARTe::QueuedMessageI() {
98 using namespace MARTe;
99 filter = ReferenceT<MessageFilterEx1>(GlobalObjectsDatabase::Instance()->GetStandardHeap());
100 filter->SetOwner(this);
101 QueuedMessageI::InstallMessageFilter(filter);
102 messageReceived = false;
103 }
104
105 virtual ~MessageEx1 () {
106 if (GetName() != NULL) {
107 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
108 "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
109 }
110 }
111
112 virtual void Purge(MARTe::ReferenceContainer &purgeList) {
113 filter->SetOwner(MARTe::Reference());
114 RemoveMessageFilter(filter);
115 }
116
117 /**
118 * @brief Print the message contents in the screen.
119 */
120 MARTe::ErrorManagement::ErrorType CheckMessage(MARTe::ReferenceT<MARTe::Message> &messageToTest) {
121 using namespace MARTe;
122 const Object *senderObj = messageToTest->GetSender();
123 CCString sender = senderObj ? senderObj->GetName() : "anonymous";
124 CCString destination = messageToTest->GetDestination();
125 CCString function = messageToTest->GetFunction();
126 bool expectsReply = messageToTest->ExpectsReply();
127 bool expectsIndirectReply = messageToTest->ExpectsIndirectReply();
128 bool isReply = messageToTest->IsReply();
129 REPORT_ERROR(MARTe::ErrorManagement::Information, "Received message from %s to %s with function %s "
130 "(expectsReply? %d expectsIndirectReply? %d isReply? %d", sender.GetList(), destination.GetList(),
131 function.GetList(), expectsReply, expectsIndirectReply, isReply);
132
133 messageReceived = true;
134 return ErrorManagement::NoError;
135 }
136
137 bool messageReceived;
138private:
139 MARTe::ReferenceT<MessageFilterEx1> filter;
140};
141
142CLASS_REGISTER(MessageEx1, "")
143
144//Delegate to the owner the handling of the message (but could be handled by the filter itself as well).
145MARTe::ErrorManagement::ErrorType MessageFilterEx1::ConsumeMessage(MARTe::ReferenceT<MARTe::Message> &messageToTest) {
146 using namespace MARTe;
147 ReferenceT<MessageEx1> ownerT = owner;
148 ErrorManagement::ErrorType err;
149 err.fatalError = !owner.IsValid();
150 if (err.ErrorsCleared()) {
151 err = ownerT->CheckMessage(messageToTest);
152 }
153 //Mark the message as a (direct) reply
154 if (err.ErrorsCleared()) {
155 messageToTest->SetAsReply(true);
156 //And insert an (example) object into
157 ReferenceT<Object> example = ReferenceT<Object>(GlobalObjectsDatabase::Instance()->GetStandardHeap());
158 example->SetName("REPLY");
159 messageToTest->Insert(example);
160 if (messageToTest->ExpectsIndirectReply()) {
161 //Indirect reply... resends the message
162 err = MessageI::SendMessage(messageToTest, this);
163 }
164 }
165 return err;
166}
167
168/**
169 * @brief A MARTe::Object class that will send indirect reply messages and wait for the reply also using a queue.
170 */
171class MessageEx2: public MARTe::ReferenceContainer, public MARTe::MessageI {
172public:
173 CLASS_REGISTER_DECLARATION()
174
175 /**
176 * @brief NOOP
177 */
178MessageEx2 () : MARTe::ReferenceContainer(), MARTe::MessageI() {
179 using namespace MARTe;
180 replyReceived = false;
181 }
182
183 virtual ~MessageEx2 () {
184 if (GetName() != NULL) {
185 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
186 "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
187 }
188 }
189
190 void SendMessages() {
191 using namespace MARTe;
192 ErrorManagement::ErrorType err;
193 //Semaphore to wait for replies
194 EventSem waitSem;
195 bool ok = waitSem.Create();
196 if (ok) {
197 ok = waitSem.Reset();
198 }
199
200 //Prepare to wait for eventual replies
201 ReferenceContainer eventReplyContainer;
202 uint32 i;
203
204 //Only accept indirect replies
205 for (i = 0u; i < Size(); i++) {
206 ReferenceT<Message> eventMsg = Get(i);
207 if (eventMsg.IsValid()) {
208 if (eventMsg->ExpectsReply()) {
209 eventMsg->SetExpectsIndirectReply(true);
210 }
211 if (eventMsg->ExpectsIndirectReply()) {
212 err = !eventReplyContainer.Insert(eventMsg);
213 }
214 }
215 }
216
217 if (ok) {
218 ok = err.ErrorsCleared();
219 }
220 //Prepare the filter which will wait for all the replies
221 if ((eventReplyContainer.Size() > 0u) && (ok)) {
222 ReferenceT<QueuedReplyMessageCatcherFilter> filter(new (NULL) QueuedReplyMessageCatcherFilter());
223 filter->SetMessagesToCatch(eventReplyContainer);
224 filter->SetEventSemaphore(waitSem);
225 err = MessageI::InstallMessageFilter(filter, 0);
226 }
227
228 ok = err.ErrorsCleared();
229 for (i = 0u; (i < Size()) && (ok); i++) {
230 ReferenceT<Message> msg = Get(i);
231 if (msg.IsValid()) {
232 msg->SetAsReply(false);
233 err = MessageI::SendMessage(msg, this);
234 }
235 ok = err.ErrorsCleared();
236 }
237 //Wait for all the replies to arrive...
238 if (ok) {
239 if (eventReplyContainer.Size() > 0u) {
240 err = waitSem.Wait(TTInfiniteWait);
241 }
242 ok = err.ErrorsCleared();
243
244 }
245 for (i = 0u; (i < Size()) && (ok); i++) {
246 ReferenceT<Message> msg = Get(i);
247 if (msg->IsReply()) {
248 REPORT_ERROR(err, "Message %s is now a reply as expected", msg->GetName());
249 }
250 if (msg->Size() > 0) {
251 Reference ref = msg->Get(0);
252 REPORT_ERROR(err, "Message %s contains an object in the reply with name %s", msg->GetName(), ref->GetName());
253 }
254 }
255 replyReceived = true;
256 }
257
258 bool replyReceived;
259};
260
261CLASS_REGISTER(MessageEx2, "")
262
263}
264/*---------------------------------------------------------------------------*/
265/* Method definitions */
266/*---------------------------------------------------------------------------*/
267
268int main(int argc, char **argv) {
269 using namespace MARTe;
270 using namespace MARTe2Tutorial;
271 SetErrorProcessFunction(&ErrorProcessExampleFunction);
272
273 StreamString configurationCfg = ""
274 "+MsgRec1 = {\n"
275 " Class = MessageEx1\n"
276 "}\n"
277 "+MsgRec2 = {\n"
278 " Class = MessageEx1\n"
279 "}\n"
280 "+MsgRec3 = {\n"
281 " Class = MessageEx1\n"
282 "}\n"
283 "+MsgSender1= {\n"
284 " Class = MessageEx2\n"
285 " +Msg1 = {\n"
286 " Class = Message\n"
287 " Destination = MsgRec3"
288 " Function = \"AFunction\""
289 " Mode = \"ExpectsIndirectReply\""
290 " }"
291 " +Msg2 = {\n"
292 " Class = Message\n"
293 " Destination = MsgRec2"
294 " Function = \"BFunction\""
295 " Mode = \"ExpectsIndirectReply\""
296 " }"
297 " +Msg3 = {\n"
298 " Class = Message\n"
299 " Destination = MsgRec1"
300 " Function = \"CFunction\""
301 " Mode = \"ExpectsIndirectReply\""
302 " }"
303 "}";
304
305 REPORT_ERROR_STATIC(ErrorManagement::Information, "Loading CFG:\n%s", configurationCfg.Buffer());
306 ConfigurationDatabase cdb;
307 StreamString err;
308 //Force the string to be seeked to the beginning.
309 configurationCfg.Seek(0LLU);
310 StandardParser parser(configurationCfg, cdb, &err);
311 bool ok = parser.Parse();
312 if (ok) {
313 //After parsing the tree is pointing at the last leaf
314 cdb.MoveToRoot();
315 ok = ObjectRegistryDatabase::Instance()->Initialise(cdb);
316 }
317 else {
318 StreamString errPrint;
319 errPrint.Printf("Failed to parse %s", err.Buffer());
320 REPORT_ERROR_STATIC(ErrorManagement::ParametersError, errPrint.Buffer());
321 }
322
323 if (ok) {
324 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully loaded the configuration file");
325 }
326
327 ReferenceT<MessageEx1> msgRec1 = ObjectRegistryDatabase::Instance()->Find("MsgRec1");
328 ReferenceT<MessageEx1> msgRec2 = ObjectRegistryDatabase::Instance()->Find("MsgRec2");
329 ReferenceT<MessageEx1> msgRec3 = ObjectRegistryDatabase::Instance()->Find("MsgRec3");
330 ReferenceT<MessageEx2> msgSender1 = ObjectRegistryDatabase::Instance()->Find("MsgSender1");
331
332 if ((msgSender1.IsValid()) && (msgRec1.IsValid()) && (msgRec2.IsValid()) && (msgRec3.IsValid())) {
333 msgRec1->Start();
334 msgRec2->Start();
335 msgRec3->Start();
336 msgSender1->SendMessages();
337 while (!msgRec1->messageReceived) {
338 Sleep::MSec(100);
339 }
340 while (!msgRec2->messageReceived) {
341 Sleep::MSec(100);
342 }
343 while (!msgRec3->messageReceived) {
344 Sleep::MSec(100);
345 }
346 while (!msgSender1->replyReceived) {
347 Sleep::MSec(100);
348 }
349 msgRec1->Stop();
350 msgRec2->Stop();
351 msgRec3->Stop();
352 }
353 //Purge all the Objects!
354 MARTe::ObjectRegistryDatabase::Instance()->Purge();
355 return 0;
356}
Remote function calls
The following is an example of remote function calls using messages.
1/**
2 * @file MessageExample5.cpp
3 * @brief Source file for class MessageExample5
4 * @date 17/04/2018
5 * @author Andre' Neto
6 *
7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
8 * the Development of Fusion Energy ('Fusion for Energy').
9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
11 * You may not use this work except in compliance with the Licence.
12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
13 *
14 * @warning Unless required by applicable law or agreed to in writing,
15 * software distributed under the Licence is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17 * or implied. See the Licence permissions and limitations under the Licence.
18
19 * @details This source file contains the definition of all the methods for
20 * the class MessageExample5 (public, protected, and private). Be aware that some
21 * methods, such as those inline could be defined on the header file, instead.
22 */
23
24#define DLL_API
25
26/*---------------------------------------------------------------------------*/
27/* Standard header includes */
28/*---------------------------------------------------------------------------*/
29
30/*---------------------------------------------------------------------------*/
31/* Project header includes */
32/*---------------------------------------------------------------------------*/
33#include "AdvancedErrorManagement.h"
34#include "CLASSMETHODREGISTER.h"
35#include "ConfigurationDatabase.h"
36#include "ErrorLoggerExample.h"
37#include "MessageI.h"
38#include "MessageFilter.h"
39#include "Object.h"
40#include "ObjectRegistryDatabase.h"
41#include "RegisteredMethodsMessageFilter.h"
42#include "Sleep.h"
43#include "StandardParser.h"
44
45/*---------------------------------------------------------------------------*/
46/* Static definitions */
47/*---------------------------------------------------------------------------*/
48namespace MARTe2Tutorial {
49
50/**
51 * @brief A MARTe::Object class that registers a set of RPC functions that can be called
52 * with messages.
53 */
54class MessageEx1: public MARTe::Object, public MARTe::MessageI {
55public:
56 CLASS_REGISTER_DECLARATION()
57
58 /**
59 * @brief Install the RegisteredMethodsMessageFilter filter.
60 */
61 MessageEx1 () : MARTe::Object(), MARTe::MessageI() {
62 using namespace MARTe;
63 filter = ReferenceT<RegisteredMethodsMessageFilter>(GlobalObjectsDatabase::Instance()->GetStandardHeap());
64 filter->SetDestination(this);
65 MessageI::InstallMessageFilter(filter);
66 }
67
68 virtual ~MessageEx1 () {
69 if (GetName() != NULL) {
70 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
71 "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
72 }
73 }
74
75 virtual void Purge(MARTe::ReferenceContainer &purgeList) {
76 RemoveMessageFilter(filter);
77 }
78
79 MARTe::ErrorManagement::ErrorType Function0 () {
80 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "Function0 called.");
81 return MARTe::ErrorManagement::NoError;
82 }
83
84 MARTe::ErrorManagement::ErrorType Function1 (MARTe::uint32 a, MARTe::float32 b) {
85 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "Received %u %f.", a, b);
86 return MARTe::ErrorManagement::NoError;
87 }
88
89 MARTe::ErrorManagement::ErrorType Function2 (MARTe::int32 &a, MARTe::float32 &b) {
90 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "Received %u %f.", a, b);
91 a = -a;
92 b = -b;
93 return MARTe::ErrorManagement::NoError;
94 }
95
96 MARTe::ErrorManagement::ErrorType Function3 (MARTe::StreamString a) {
97 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "Received %s.", a.Buffer());
98 return MARTe::ErrorManagement::NoError;
99 }
100
101private:
102 MARTe::ReferenceT<MARTe::RegisteredMethodsMessageFilter> filter;
103};
104
105CLASS_REGISTER(MessageEx1, "")
106CLASS_METHOD_REGISTER(MessageEx1, Function0)
107CLASS_METHOD_REGISTER(MessageEx1, Function1)
108CLASS_METHOD_REGISTER(MessageEx1, Function2)
109CLASS_METHOD_REGISTER(MessageEx1, Function3)
110
111/**
112 * @brief A MARTe::Object class that will send indirect reply messages and waits for the reply.
113 * Note that the method SendMessageAndWaitIndirectReply will automatically register a ReplyMessageCatcherMessageFilter filter
114 */
115class MessageEx2: public MARTe::ReferenceContainer, public MARTe::MessageI {
116public:
117 CLASS_REGISTER_DECLARATION()
118
119 /**
120 * @brief NOOP
121 */
122 MessageEx2 () : MARTe::ReferenceContainer(), MARTe::MessageI() {
123 using namespace MARTe;
124 replyReceived = false;
125 }
126
127 virtual ~MessageEx2 () {
128 if (GetName() != NULL) {
129 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
130 "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
131 }
132 }
133
134 void SendMessages() {
135 using namespace MARTe;
136 uint32 numberOfMessages = Size();
137 uint32 i;
138 for (i=0u; i<numberOfMessages; i++) {
139 ReferenceT<Message> msg = Get(i);
140 ErrorManagement::ErrorType err;
141 err.fatalError = !msg.IsValid();
142 if (err.ErrorsCleared()) {
143 if (!msg->ExpectsIndirectReply()) {
144 msg->SetExpectsIndirectReply(true);
145 }
146 err = SendMessageAndWaitIndirectReply(msg);
147 REPORT_ERROR(err, "Message %s sent", msg->GetName());
148 }
149 if (err.ErrorsCleared()) {
150 if (msg->IsReply()) {
151 REPORT_ERROR(err, "Message %s is now a reply as expected", msg->GetName());
152 ReferenceT<ConfigurationDatabase> params;
153 if (msg->Size() > 0) {
154 params = msg->Get(0);
155 }
156 if (params.IsValid()) {
157 REPORT_ERROR(err, "Replied parameters %!", *(params.operator ->()));
158 }
159 }
160 }
161 }
162 replyReceived = true;
163 }
164
165 bool replyReceived;
166};
167
168CLASS_REGISTER(MessageEx2, "")
169
170}
171/*---------------------------------------------------------------------------*/
172/* Method definitions */
173/*---------------------------------------------------------------------------*/
174
175int main(int argc, char **argv) {
176 using namespace MARTe;
177 using namespace MARTe2Tutorial;
178 SetErrorProcessFunction(&ErrorProcessExampleFunction);
179
180 StreamString configurationCfg = ""
181 "+MsgRec1 = {\n"
182 " Class = MessageEx1\n"
183 "}\n"
184 "+MsgSender1= {\n"
185 " Class = MessageEx2\n"
186 " +Msg0 = {\n"
187 " Class = Message\n"
188 " Destination = MsgRec1"
189 " Function = \"Function0\""
190 " Mode = \"ExpectsIndirectReply\""
191 " }"
192 " +Msg1 = {\n"
193 " Class = Message\n"
194 " Destination = MsgRec1"
195 " Function = \"Function1\""
196 " Mode = \"ExpectsIndirectReply\""
197 " +Parameters = {"
198 " Class = ConfigurationDatabase"
199 " param1 = 2"
200 " param2 = 3.14"
201 " }"
202 " }"
203 " +Msg2 = {\n"
204 " Class = Message\n"
205 " Destination = MsgRec1"
206 " Function = \"Function2\""
207 " Mode = \"ExpectsIndirectReply\""
208 " +Parameters = {"
209 " Class = ConfigurationDatabase"
210 " param1 = 2"
211 " param2 = 3.14"
212 " }"
213 " }"
214 " +Msg3 = {\n"
215 " Class = Message\n"
216 " Destination = MsgRec1"
217 " Function = \"Function3\""
218 " Mode = \"ExpectsIndirectReply\""
219 " +Parameters = {"
220 " Class = ConfigurationDatabase"
221 " param1 = \"This is a string\""
222 " }"
223 " }"
224 "}";
225
226 REPORT_ERROR_STATIC(ErrorManagement::Information, "Loading CFG:\n%s", configurationCfg.Buffer());
227 ConfigurationDatabase cdb;
228 StreamString err;
229 //Force the string to be seeked to the beginning.
230 configurationCfg.Seek(0LLU);
231 StandardParser parser(configurationCfg, cdb, &err);
232 bool ok = parser.Parse();
233 if (ok) {
234 //After parsing the tree is pointing at the last leaf
235 cdb.MoveToRoot();
236 ok = ObjectRegistryDatabase::Instance()->Initialise(cdb);
237 }
238 else {
239 StreamString errPrint;
240 errPrint.Printf("Failed to parse %s", err.Buffer());
241 REPORT_ERROR_STATIC(ErrorManagement::ParametersError, errPrint.Buffer());
242 }
243
244 if (ok) {
245 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully loaded the configuration file");
246 }
247
248 ReferenceT<MessageEx1> msgRec1 = ObjectRegistryDatabase::Instance()->Find("MsgRec1");
249 ReferenceT<MessageEx2> msgSender1 = ObjectRegistryDatabase::Instance()->Find("MsgSender1");
250
251 if ((msgSender1.IsValid()) && (msgRec1.IsValid())) {
252 msgSender1->SendMessages();
253
254 while (!msgSender1->replyReceived) {
255 Sleep::MSec(100);
256 }
257 }
258 //Purge all the Objects!
259 MARTe::ObjectRegistryDatabase::Instance()->Purge();
260 return 0;
261}
Configuration management
The following is an example of how to update the framework configuration in runtime.
1/**
2 * @file MessageExample6.cpp
3 * @brief Source file for class MessageExample6
4 * @date 17/04/2018
5 * @author Andre' Neto
6 *
7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
8 * the Development of Fusion Energy ('Fusion for Energy').
9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
11 * You may not use this work except in compliance with the Licence.
12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
13 *
14 * @warning Unless required by applicable law or agreed to in writing,
15 * software distributed under the Licence is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17 * or implied. See the Licence permissions and limitations under the Licence.
18
19 * @details This source file contains the definition of all the methods for
20 * the class MessageExample6 (public, protected, and private). Be aware that some
21 * methods, such as those inline could be defined on the header file, instead.
22 */
23
24#define DLL_API
25
26/*---------------------------------------------------------------------------*/
27/* Standard header includes */
28/*---------------------------------------------------------------------------*/
29#include <stdio.h>
30
31/*---------------------------------------------------------------------------*/
32/* Project header includes */
33/*---------------------------------------------------------------------------*/
34#include "AdvancedErrorManagement.h"
35#include "CLASSMETHODREGISTER.h"
36#include "ConfigurationDatabase.h"
37#include "ErrorLoggerExample.h"
38#include "MessageI.h"
39#include "MessageFilter.h"
40#include "Object.h"
41#include "ObjectRegistryDatabase.h"
42#include "RegisteredMethodsMessageFilter.h"
43#include "Sleep.h"
44#include "StandardParser.h"
45
46/*---------------------------------------------------------------------------*/
47/* Static definitions */
48/*---------------------------------------------------------------------------*/
49namespace MARTe2Tutorial {
50
51void DumpObjectRegistryDatabase(MARTe::ReferenceContainer &rc, MARTe::uint32 depth) {
52 MARTe::uint32 i;
53 for (i = 0u; i < depth; i++) {
54 printf(" ");
55 }
56 for (i = 0u; i < rc.Size(); i++) {
57 MARTe::ReferenceT<MARTe::Object> rco = rc.Get(i);
58 if (rco.IsValid()) {
59 printf("[%s]\n", rco->GetName());
60 }
61 MARTe::ReferenceT<MARTe::ReferenceContainer> rcn = rc.Get(i);
62 if (rcn.IsValid()) {
63 DumpObjectRegistryDatabase(*rcn.operator ->(), depth + 1);
64 }
65 }
66 printf("\n");
67}
68}
69/*---------------------------------------------------------------------------*/
70/* Method definitions */
71/*---------------------------------------------------------------------------*/
72
73int main(int argc, char **argv) {
74 using namespace MARTe;
75 using namespace MARTe2Tutorial;
76 SetErrorProcessFunction(&ErrorProcessExampleFunction);
77 StreamString err;
78
79 bool ok = true;
80 {
81 StreamString configurationCfg = ""
82 "+ConfigurationManager = {\n"
83 " Class = ObjectRegistryDatabaseMessageI\n"
84 "}";
85 //Force the string to be seeked to the beginning.
86 configurationCfg.Seek(0LLU);
87
88 REPORT_ERROR_STATIC(ErrorManagement::Information, "Loading CFG:\n%s", configurationCfg.Buffer());
89 ConfigurationDatabase cdb;
90
91 StandardParser parser(configurationCfg, cdb, &err);
92 parser.Parse();
93 if (ok) {
94 //After parsing the tree is pointing at the last leaf
95 cdb.MoveToRoot();
96 ok = ObjectRegistryDatabase::Instance()->Initialise(cdb);
97 }
98 else {
99 StreamString errPrint;
100 errPrint.Printf("Failed to parse %s", err.Buffer());
101 REPORT_ERROR_STATIC(ErrorManagement::ParametersError, errPrint.Buffer());
102 }
103 }
104 if (ok) {
105 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully loaded the configuration file");
106 DumpObjectRegistryDatabase(*ObjectRegistryDatabase::Instance(), 0u);
107 }
108 //Reload a new configuration
109 if (ok) {
110 StreamString app1Cfg = ""
111 "+App1 = {\n"
112 " Class = ReferenceContainer\n"
113 " +A = {\n"
114 " Class = ReferenceContainer\n"
115 " +B = {\n"
116 " Class = ReferenceContainer\n"
117 " }\n"
118 " }\n"
119 "}";
120 ReferenceT<ConfigurationDatabase> cdbApp1(GlobalObjectsDatabase::Instance()->GetStandardHeap());
121 app1Cfg.Seek(0LLU);
122 StandardParser parserApp1(app1Cfg, *cdbApp1.operator ->(), &err);
123 ok = parserApp1.Parse();
124 if (ok) {
125 //After parsing the tree is pointing at the last leaf
126 ReferenceT<Message> msg(GlobalObjectsDatabase::Instance()->GetStandardHeap());
127 ConfigurationDatabase cdbMsg;
128 cdbMsg.Write("Function", "load");
129 cdbMsg.Write("Destination", "ConfigurationManager");
130 cdbApp1->MoveToRoot();
131 msg->Initialise(cdbMsg);
132 msg->Insert(cdbApp1);
133 ErrorManagement::ErrorType err = MessageI::SendMessage(msg);
134 ok = err.ErrorsCleared();
135 if (ok) {
136 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully loaded the app1 configuration");
137 DumpObjectRegistryDatabase(*ObjectRegistryDatabase::Instance(), 0u);
138 }
139 }
140 }
141 //Change the configuration (purge first)
142 if (ok) {
143 ReferenceT<Message> msg(GlobalObjectsDatabase::Instance()->GetStandardHeap());
144 ConfigurationDatabase cdbMsg;
145 cdbMsg.Write("Function", "purge");
146 cdbMsg.Write("Destination", "ConfigurationManager");
147 ReferenceT<ConfigurationDatabase> cdbMsgPayload(GlobalObjectsDatabase::Instance()->GetStandardHeap());
148 cdbMsgPayload->Write("Root", "App1");
149 msg->Initialise(cdbMsg);
150 msg->Insert(cdbMsgPayload);
151 ErrorManagement::ErrorType err = MessageI::SendMessage(msg);
152 ok = err.ErrorsCleared();
153 if (ok) {
154 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully purged the app1 configuration");
155 DumpObjectRegistryDatabase(*ObjectRegistryDatabase::Instance(), 0u);
156 }
157 }
158 if (ok) {
159 StreamString app2Cfg = ""
160 "+App1 = {\n"
161 " Class = ReferenceContainer\n"
162 " +A = {\n"
163 " Class = ReferenceContainer\n"
164 " +C = {\n"
165 " Class = ReferenceContainer\n"
166 " +B = {\n"
167 " Class = ReferenceContainer\n"
168 " }\n"
169 " }\n"
170 " }\n"
171 "}";
172
173 ReferenceT<ConfigurationDatabase> cdbApp2(GlobalObjectsDatabase::Instance()->GetStandardHeap());
174 app2Cfg.Seek(0LLU);
175 StandardParser parserApp2(app2Cfg, *cdbApp2.operator ->(), &err);
176 ok = parserApp2.Parse();
177 if (ok) {
178 //After parsing the tree is pointing at the last leaf
179 ReferenceT<Message> msg(GlobalObjectsDatabase::Instance()->GetStandardHeap());
180 ConfigurationDatabase cdbMsg;
181 cdbMsg.Write("Function", "load");
182 cdbMsg.Write("Destination", "ConfigurationManager");
183 msg->Initialise(cdbMsg);
184 msg->Insert(cdbApp2);
185 ErrorManagement::ErrorType err = MessageI::SendMessage(msg);
186 ok = err.ErrorsCleared();
187 if (ok) {
188 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully loaded the app2 configuration");
189 DumpObjectRegistryDatabase(*ObjectRegistryDatabase::Instance(), 0u);
190 }
191 }
192 }
193 //Purge all the Objects!
194 MARTe::ObjectRegistryDatabase::Instance()->Purge();
195 return 0;
196}