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

../../_images/Messages-0.png

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.

../../_images/Messages-1.png

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);
 }
../../_images/Messages-2.png ../../_images/Messages-3.png

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.

../../_images/Messages-6.png

Original message instance …

../../_images/Messages-4.png

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

../../_images/Messages-5.png
...
//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.

../../_images/Messages-7.png ../../_images/Messages-4A.png

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

ObjectRegistryDatabaseMessageFilter

Allows to manage (purge and load) the ObjectRegistryDatabase and thus change the configuration of the application in runtime (see example below).

RegisteredMethodsMessageFilter

Enables the call of remote Object functions using messages (see below).

ReplyMessageCatcherMessageFilter

Waits for a given reply to arrive. Typically used with indirect messages.

QueueingMessageFilter

Listens for messages in the context of a different thread and puts the messages in a queue (shall be used with a QueuedMessageI).

QueuedReplyMessageCatcherFilter

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.

Sending of direct 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
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.

Sending of direct messages 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.

Sending of indirect messages 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.

Queued messages (note the usage of the QueuedMessageI).
  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.

Remote functions calling 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.

Change of configuration 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
/**
 * @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;
}