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