HTTP

The HTTP service (see HttpService) enables the interaction with MARTe2 based applications using the HTTP protocol. In particular it allows to query live information (using JSON) about any Object through the ExportData method.

HttpDataExportI

In order to be able to interact directly with an HttpService instance, a class must implement the HttpDataExportI interface. Depending on the type of request, the HttpService will either call the GetAsStructuredData or the GetAsText function. The former is expected to return data structured using a StructuredDataI interface, while the latter is aimed at writing free text (e.g. HTML).

The type of request can be set by including in the URL query string the parameter TextMode=0 or TextMode=1.

virtual bool GetAsStructuredData(MARTe::StreamStructuredDataI &data, MARTe::HttpProtocol &protocol) {
    bool ok = HttpDataExportI::GetAsStructuredData(data, protocol);
    ...
    ok = data.Write("Counter", counter);
    ...

virtual bool GetAsText(MARTe::StreamI &stream, MARTe::HttpProtocol &protocol) {
    bool ok = HttpDataExportI::GetAsText(stream, protocol);
    MARTe::StreamString txt;
    ...
    ok = txt.Printf("<html><body><h1>Counter = %d</h1></body></html>\n", counter);
    ...
    ok = stream.Write(txt.Buffer(), nBytes);
    ...

Warning

The data model and the data presentation layers should be as decoupled as possible. As a consequence, for the majority of use-cases, objects should not implement the HTTPDataExportI interface. Instead, objects should expose data using the ExportData method. It is assumed that all the data visualisation features are delegated to the HTTP client.

HttpObjectBrowser

The HttpObjectBrowser enables the HTTP browsing of any ReferenceContainer. Using such feature one can query information about any component in a given MARTe application instance.

The HttpObjectBrowser can be configured to point at its own childs Root=., at the root of the application Root=/ or at any given MARTe object Root=Path.To.Obj. By setting the Realm option (see HttpRealmI), the access to resources will be constrained to users that have valid credentials.

When accessing to an HttpObjectBrowser with text mode, the instance will check if there is an HttpDirectoryResource child instance capable of handling the request and if so forwards the request to it. This mechanism can be used, e.g. to return an index.html page.

+WebRoot = {
    Class = HttpObjectBrowser
    Root = "." //Navigation w.r.t. to this object
    +ObjectBrowse = {
        Class = HttpObjectBrowser
        Root = "/" //Navigation w.r.t. to the ObjectRegistryDatabase root
    }
    +ResourcesHtml = {
        Class = HttpDirectoryResource //If TextMode=1 will try to see if the component can resolve the request
        BaseDir = "../../../../../Resources/HTTP/"
    }

HttpMessageInterface

Using the HttpMessageInterface it is possible to send command to a MARTe application using the URL query string. These commands are interpreted and forward as MARTe messages.

...
+HttpMessageInterface = {
    Class = HttpMessageInterface
    +GOTOIDLE = { //Trigger the message GOTOIDLE if the URL contains msg=GOTOIDLE
        Class = Message
        Destination = StateMachine
        Function = GOTOIDLE
        Mode = ExpectsReply
    }
...

JavaScript client

MARTe2 ships with a simple JavaScript based client framework that aims at easing the development of graphical user-interfaces.

Note

For more complex client applications, users should use the JSON interface and design their own client applications.

The MARTe2 JavaScript client (see Resources/HTTP on the project folder) is based on a plug-in mechanism which retrieves data from the server (using JSON) and offers it to a given class that inherits from the MARTeObject JavaScript class.

...
class HttpPendulumEx1 extends MARTeObject {
...
    displayData(jsonData) {
        var angle = parseFloat(jsonData["angle"]);
        var width = this.canvas.clientWidth;
        var height = this.canvas.clientHeight;
...

These classes can be instantiated and associated to a given JSON data stream using the MARTeLoader singleton. In particular the load method allows to allocate a given instance of the provided class to an HTML element and later associated to a JSON data source.

...
var mainTargetContainer = document.getElementById("mainTarget");
//Associate the HttpPendulumEx1P2.js to an HTML element identified by the id "table0x1" and load with data coming from http://.../Pendulum
MARTeLoader.instance().load("Pendulum", "HttpPendulumEx1P2", "table0x1");
...

The HttpObjectBrowser is a plug-in implementation that offers a navigation tree and that allows to display the selected class instance in a given display pane.

Note

Objects, such as the ThreadsInformationQuery, can be used to easily export live information about a running system.

The HttpClient allows to develop HTTP clients and is used as a core class for many of the HTTP service tests.

Examples

This example shows how to instantiate an HttpService and how to interface directly to an HttpDataExportI. After starting the application, point a browser at http://localhost:8084/

Introspection of live objects using HTTP.
  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
/**
 * @file HttpExample1.cpp
 * @brief Source file for class HttpExample1
 * @date 26/10/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 HttpExample1 (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 <math.h>
#include <signal.h>

/*---------------------------------------------------------------------------*/
/*                         Project header includes                           */
/*---------------------------------------------------------------------------*/
#include "AdvancedErrorManagement.h"
#include "BasicConsole.h"
#include "ClassRegistryDatabase.h"
#include "ClassRegistryItemT.h"
#include "ConfigurationDatabase.h"
#include "ErrorLoggerExample.h"
#include "HighResolutionTimer.h"
#include "HttpDataExportI.h"
#include "HttpDefinition.h"
#include "HttpService.h"
#include "Object.h"
#include "ObjectRegistryDatabase.h"
#include "Reference.h"
#include "ReferenceT.h"
#include "StandardParser.h"
#include "StreamString.h"
#include "StructuredDataI.h"

/*---------------------------------------------------------------------------*/
/*                           Static definitions                              */
/*---------------------------------------------------------------------------*/
static bool keepRunning = true;
static MARTe::float32 timeStepPeriod = 1e-2;
static void StopApp(int sig) {
    keepRunning = false;
}

/*---------------------------------------------------------------------------*/
/*                           Method definitions                              */
/*---------------------------------------------------------------------------*/

namespace MARTe2Tutorial {
/**
 * @brief A MARTe::Object class that will expose its properties using the DataExportI interface.
 */
class HttpObjectEx1: public MARTe::Object {
public:
    CLASS_REGISTER_DECLARATION()

    /**
     * @brief NOOP.
     */
    HttpObjectEx1() : Object() {
        counter = 10u;
    }

    virtual ~HttpObjectEx1 () {
        if (GetName() != NULL_PTR(const MARTe::char8 *)) {
            REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
                    "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
        }
    }

    virtual bool ExportData(MARTe::StructuredDataI & data) {
        bool ok = Object::ExportData(data);
        counter++;
        if (counter == 30u) {
            counter = 10u;
        }
        if (ok) {
            ok = data.Write("Counter", counter);
        }
        return ok;
    }

private:
    MARTe::uint32 counter;

};
CLASS_REGISTER(HttpObjectEx1, "1.0")

/**
 * @brief A MARTe::Object class that will expose its properties using the HttpDataExportI interface.
 */
class HttpObjectEx2: public MARTe::Object, public MARTe::HttpDataExportI {
public:
    CLASS_REGISTER_DECLARATION()

    /**
     * @brief NOOP.
     */
    HttpObjectEx2() : Object() {
        counter = 10u;
    }

    virtual ~HttpObjectEx2 () {
        if (GetName() != NULL_PTR(const MARTe::char8 *)) {
            REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
                    "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
        }
    }

    virtual bool GetAsStructuredData(MARTe::StreamStructuredDataI &data, MARTe::HttpProtocol &protocol) {
        bool ok = HttpDataExportI::GetAsStructuredData(data, protocol);
        if (ok) {
            ok = MARTe::Object::ExportData(data);
        }
        counter++;
        if (counter == 30u) {
            counter = 10u;
        }
        if (ok) {
            ok = data.Write("Counter", counter);
        }
        return ok;

    }

    virtual bool GetAsText(MARTe::StreamI &stream, MARTe::HttpProtocol &protocol) {
        bool ok = HttpDataExportI::GetAsText(stream, protocol);
        MARTe::StreamString txt;
        if (ok) {
            ok = txt.Printf("<html><body><h1>Counter = %d</h1></body></html>\n", counter);
        }
        if (ok) {
            MARTe::uint32 nBytes = txt.Size();
            ok = stream.Write(txt.Buffer(), nBytes);
        }
        return ok;
    }

private:
    MARTe::uint32 counter;

};
CLASS_REGISTER(HttpObjectEx2, "1.0")


/**
 * @brief A MARTe::Object class that will expose its properties using the DataExportI interface.
 */
class HttpPendulumEx1: public MARTe::Object {
public:
    CLASS_REGISTER_DECLARATION()

    /**
     * @brief NOOP.
     */
    HttpPendulumEx1() : Object() {
        velocity = 0;
        angle = 3.1415 / 3;
        gravity = -9.8;
        length = 1;
        timeStepCounter = 0;
    }

    virtual ~HttpPendulumEx1 () {
        if (GetName() != NULL_PTR(const MARTe::char8 *)) {
            REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
                    "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
        }
    }

    virtual bool ExportData(MARTe::StructuredDataI & data) {
        bool ok = Object::ExportData(data);
        if (ok) {
            ok = data.Write("angle", angle);
        }
        return ok;
    }

    void Execute() {
        MARTe::float32 acceleration = gravity / length * sinf(angle);
        velocity += acceleration * timeStepPeriod;
        angle += velocity * timeStepPeriod;
        timeStepCounter++;
        //REPORT_ERROR_STATIC(MARTe::ErrorManagement::Debug, "Time = %f Angle = %f", timeStepPeriod, angle);
    }

private:
    MARTe::float32 length;
    MARTe::float32 velocity;
    MARTe::float32 angle;
    MARTe::float32 gravity;
    MARTe::uint32 timeStepCounter;

};
CLASS_REGISTER(HttpPendulumEx1, "1.0")
}

int main(int argc, char **argv) {
    using namespace MARTe;
    using namespace MARTe2Tutorial;
    SetErrorProcessFunction(&ErrorProcessExampleFunction);

    StreamString config = ""
            "+WebRoot = {"
            "    Class = HttpObjectBrowser"
            "    Root = \".\""
            "    +TheRoot = {"
            "        Root = \"/\""
            "        Class = HttpObjectBrowser"
            "    }"
            "    +ARootObj1 = {"
            "        Class = HttpObjectBrowser"
            "        Root = \".\""
            "        +AChildObj1 = {"
            "            Class = HttpObjectEx1"
            "        }"
            "        +Obj2 = {"
            "            Class = HttpObjectEx1"
            "        }"
            "    }"
            "    +ARootObj2 = {"
            "        Class = HttpObjectEx1"
            "    }"
            "    +ARootObj3 = {"
            "        Class = HttpObjectEx1"
            "    }"
            "    +Pendulum = {"
            "        Class = HttpPendulumEx1"
            "    }"
            "    +ResourcesHtml = {"
            "        Class = HttpDirectoryResource"
            "        BaseDir = \"../../../../../../Resources/HTTP/\""
            "    }"
            "    +ResourcesJS = {"
            "        Class = HttpDirectoryResource"
            "        BaseDir = \"../../../../../../Resources/HTTP/JS/\""
            "    }"
            "    +ResourcesJS2 = {"
            "        Class = HttpDirectoryResource"
            "        BaseDir = \"../Resources/HTTP/\""
            "    }"
            "    +ThreadsInformationQuery = {"
            "        Class = ThreadsInformationQuery"
            "    }"
            "}"
            "+WebServer = {"
            "    Class = HttpService"
            "    Port = 8084"
            "    WebRoot = WebRoot"
            "    Timeout = 0"
            "    ListenMaxConnections = 255"
            "    AcceptTimeout = 1000"
            "    MaxNumberOfThreads = 64"
            "    MinNumberOfThreads = 1"
            "}";

    REPORT_ERROR_STATIC(ErrorManagement::Information, "Loading CFG:\n%s", config.Buffer());
    ConfigurationDatabase cdb;
    StreamString err;
    //Force the string to be seeked to the beginning.
    config.Seek(0LLU);
    StandardParser parser(config, 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<HttpService> service = ObjectRegistryDatabase::Instance()->Find("WebServer");
    if (ok) {
        ok = service.IsValid();
    }
    if (ok) {
        ok = service->Start();
    }
    StreamString msg = "Type Ctrl + C to exit\n";
    BasicConsole con;
    con.Open(BasicConsoleMode::PerformCharacterInput);
    con.SetSceneSize(64, 1);
    uint32 msgSize = msg.Size();
    con.Write(msg.Buffer(), msgSize);
    ReferenceT<HttpPendulumEx1> pendulum = ObjectRegistryDatabase::Instance()->Find("WebRoot.Pendulum");
    signal(SIGTERM, StopApp);
    signal(SIGINT, StopApp);
    if (ok) {
        ok = pendulum.IsValid();
    }
    if (ok) {
        while (keepRunning) {
            pendulum->Execute();
            Sleep::Sec(timeStepPeriod);
        }
    }
    if (ok) {
        ok = service->Stop();
    }
    return 0;
}

For the example above, the Pendulum JavaScript class was coded as below:

Development of JavaScript plugins that can be integrated into client applications.
 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
/**
 * @file HttpPendulumEx1.js 
 * @date 28/03/2019
 * @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
 * 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.
 */
/**
 * Default plugin renderer for a pendulum.
 */
class HttpPendulumEx1 extends MARTeObject {

    /**
     * NOOP
     */
    constructor() {
        super();
        this.pcolor = "yellow";
    }


    /**
     * Creates the canvas.
     *
     * @param {obj} target the target HTML container where to display the data.
     */
    prepareDisplay(target) {
        this.canvas = document.createElement("canvas");
        this.canvas.setAttribute("class", "pendulumCanvas");
        this.context = this.canvas.getContext("2d");
        target.innerHTML = "";
        target.appendChild(this.canvas);
        this.refresh(100);
    }

    /**
     * Updates the pendulum with the new angle position.
     *
     * @param {obj} jsonData the data as received by the server and which should contain the angle.
     */
    displayData(jsonData) {
        var angle = parseFloat(jsonData["angle"]);
        var width = this.canvas.clientWidth;
        var height = this.canvas.clientHeight;
        var length = Math.min(width, height);
        var rPend = length * 0.4;
        var rBall = length * 0.04;
        var rBar = length * 0.004;
        var ballX = Math.sin(angle) * rPend;
        var ballY = Math.cos(angle) * rPend;
        this.context.fillStyle = "white";
        this.context.fillRect(0, 0, width, height);
        this.context.save();
        this.context.translate(width/2, 10);
        this.context.rotate(angle);
        this.context.beginPath();
        this.context.rect(-rBar, -rBar, rBar*2, rPend+rBar*2);
        this.context.strokeStyle = "black";
        this.context.fillStyle = "black";
        this.context.fill();
        this.context.stroke();
        this.context.beginPath();
        this.context.arc(0, rPend, rBall, 0, Math.PI*2, false);
        this.context.fillStyle = this.pcolor;
        this.context.fill();
        this.context.stroke();
        this.context.restore();
    }

    /**
     * Sets the pendulum color.
     *
     * @param {color} c the new pendulum color.
     */
    setColor(c) {
        this.pcolor = c;
    }
}

Adding an HttpService to an existent MARTe application can be used to query live information about GAM signals and to change the StateMachine status. After starting the application, point a browser at http://localhost:8084 and navigate to the different GAMs. Also change the state machine state by interacting with the HttpMessageInterface component.

Integration of an HttpService into an existent application (Run with MESSAGE=StateMachine:START and NAME_OF_THE_CONFIGURATION_FILE=RTApp-5.cfg)
  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
357
358
359
360
361
362
363
+WebRoot = {
    Class = HttpObjectBrowser
    Root = "."
    +ObjectBrowse = {
        Class = HttpObjectBrowser
        Root = "/"
    }
    +ResourcesHtml = {
        Class = HttpDirectoryResource
        BaseDir = "../../../../../Resources/HTTP/"
    }    
    +HttpMessageInterface = {
        Class = HttpMessageInterface
        +GOTOIDLE = {
            Class = Message
            Destination = StateMachine
            Function = GOTOIDLE
            Mode = ExpectsReply
        }
        +GOTORUN = {
            Class = Message
            Destination = StateMachine
            Function = GOTORUN
            Mode = ExpectsReply
        }
        +GOTOERR = {
            Class = Message
            Destination = StateMachineError
            Function = GOTOERR 
            Mode = ExpectsReply
        }
    }
}
+WebServer = {
    Class = HttpService
    Port = 8084
    WebRoot = WebRoot
    Timeout = 0
    ListenMaxConnections = 255
    AcceptTimeout = 1000
    MaxNumberOfThreads = 8
    MinNumberOfThreads = 1
}
+StateMachine = {
    Class = StateMachine
    +INITIAL = {
        Class = ReferenceContainer      
        +START = {
            Class = StateMachineEvent
            NextState = "IDLE"
            NextStateError = "IDLE"
            Timeout = 0
            +StartHttpServer = {
                Class = Message
                Destination = "WebServer"
                Function = "Start"
                Mode = ExpectsReply
            }            
            +ChangeToStateIdleMsg = {
                Class = Message
                Destination = TestApp
                Mode = ExpectsReply
                Function = PrepareNextState
                +Parameters = {
                    Class = ConfigurationDatabase
                    param1 = Idle
                }
            }
            +StartNextStateExecutionMsg = {
                Class = Message
                Destination = TestApp
                Function = StartNextStateExecution
                Mode = ExpectsReply
            }
        }
    }
    +IDLE = {
        Class = ReferenceContainer
        +GOTORUN = {
            Class = StateMachineEvent
            NextState = "RUN"
            NextStateError = "IDLE"
            Timeout = 0 
            +ChangeToRunMsg = {
                Class = Message
                Destination = TestApp
                Mode = ExpectsReply
                Function = PrepareNextState
                +Parameters = {
                    Class = ConfigurationDatabase
                    param1 = Run
                }
            }
            +StopCurrentStateExecutionMsg = {
                Class = Message
                Destination = TestApp
                Function = StopCurrentStateExecution
                Mode = ExpectsReply
            }
            +StartNextStateExecutionMsg = {
                Class = Message
                Destination = TestApp
                Function = StartNextStateExecution
                Mode = ExpectsReply
            }
        }
    }
    +RUN = {
        Class = ReferenceContainer
        +GOTOIDLE = {
            Class = StateMachineEvent
            NextState = "IDLE"
            NextStateError = "IDLE"
            Timeout = 0         
            +ChangeToIdleMsg = {
                Class = Message
                Destination = TestApp
                Mode = ExpectsReply
                Function = PrepareNextState
                +Parameters = {
                    Class = ConfigurationDatabase
                    param1 = Idle
                }
            }
            +StopCurrentStateExecutionMsg = {
                Class = Message
                Destination = TestApp
                Function = StopCurrentStateExecution
                Mode = ExpectsReply
            }
            +StartNextStateExecutionMsg = {
                Class = Message
                Destination = TestApp
                Function = StartNextStateExecution
                Mode = ExpectsReply
            }
        }   
    }
}
$TestApp = {
    Class = RealTimeApplication
    +Functions = {
        Class = ReferenceContainer
        +GAMTimer = {
            Class = IOGAM
            InputSignals = {
                Counter = {
                    DataSource = Timer
                    Type = uint32
                }
                Time = {
                    Frequency = 1
                    DataSource = Timer
                    Type = uint32
                }
            }
            OutputSignals = {
                Counter = {
                    DataSource = DDB1
                    Type = uint32
                }
                Time = {
                    DataSource = DDB1
                    Type = uint32
                }
            }
        }
        +GAMFixed1 = {
            Class = FixedGAMExample1
            Gain = 2
            InputSignals = {
                Counter = {
                    DataSource = DDB1
                    Type = uint32
                }
            }
            OutputSignals = {
                GainCounter = {
                    DataSource = DDB1
                    Type = uint32
                }
            }
        }
        +GAMGroup1 = {
            Class = ParentGAMGroupExample1
            Model = {{2, 0, 0}, {0, 3, 0}, {1, 0, 4}}
            +GAMChild1 = {
                Class = ChildGAMGroupExample1
                InputSignals = {
                    Signal3 = {
                        DataSource = DDB1
                        Type = uint32
                        NumberOfDimensions = 1
                        NumberOfElements = 3
                    }
                }
                OutputSignals = {
                    Signal1 = {
                        DataSource = DDB1
                        Type = uint32
                        NumberOfDimensions = 1 
                        NumberOfElements = 3
                        Default = {1, 1, 1}
                    }
                 }
            } 
            +GAMChild2 = {
                Class = ChildGAMGroupExample2
                InputSignals = {
                    Signal1 = {
                        DataSource = DDB1
                        Type = uint32
                        NumberOfDimensions = 1
                        NumberOfElements = 3
                    }
                }
                OutputSignals = {
                    Signal2 = {
                        DataSource = DDB1
                        Type = uint32
                        NumberOfDimensions = 1 
                        NumberOfElements = 3
                        Default = {1, 1, 1}
                    }
                 }
            }
            +GAMChild3 = {
                Class = ChildGAMGroupExample1
                InputSignals = {
                    Signal2 = {
                        DataSource = DDB1
                        Type = uint32
                        NumberOfDimensions = 1 
                        NumberOfElements = 3
                    }
                }
                OutputSignals = {
                    Signal3 = {
                        DataSource = DDB1
                        Type = uint32
                        NumberOfDimensions = 1 
                        NumberOfElements = 3
                        Default = {1, 1, 1}
                    }
                }
             }
        }
        +GAMDisplay = {
            Class = IOGAM
            InputSignals = {
                Counter = {
                    DataSource = DDB1
                    Type = uint32
                    Default = 100
                }
                GainCounter = {
                    DataSource = DDB1
                    Type = uint32
                }
                Signal1 = {
                    DataSource = DDB1
                    Type = uint32
                }
                Signal2 = {
                    DataSource = DDB1
                    Type = uint32
                }
                //Print only the first and the last element of Signal 3
                Signal3 = {
                    DataSource = DDB1
                    Type = uint32
                    Ranges = {{0,0}, {2, 2}}
                    NumberOfElements = 3
                    NumberOfDimensions = 1
                }
            }
            OutputSignals = {
                Counter = {
                    DataSource = LoggerDataSource
                    Type = uint32
                }
                GainCounter = {
                    DataSource = LoggerDataSource
                    Type = uint32
                } 
                Signal1 = {
                    DataSource = LoggerDataSource
                    Type = uint32
                    NumberOfElements = 3
                    NumberOfDimensions = 1
                }              
                Signal2 = {
                    DataSource = LoggerDataSource
                    Type = uint32
                    NumberOfElements = 3
                    NumberOfDimensions = 1
                }
                Signal3FirstAndLast = {
                    DataSource = LoggerDataSource
                    Type = uint32
                    NumberOfElements = 2
                    NumberOfDimensions = 1
                }
            }
        }
    }
    +Data = {
        Class = ReferenceContainer
        DefaultDataSource = DDB1
        +DDB1 = {
            Class = GAMDataSource
        }        
        +LoggerDataSource = {
            Class = LoggerDataSource
        }
        +Timings = {
            Class = TimingDataSource
        }
        +Timer = {
            Class = LinuxTimer
            SleepNature = "Default"
            Signals = {
                Counter = {
                    Type = uint32
                }
                Time = {
                    Type = uint32
                }
            }
        }
    }
    +States = {
        Class = ReferenceContainer
        +Idle = {
            Class = RealTimeState
            +Threads = {
                Class = ReferenceContainer
                +Thread1 = {
                    Class = RealTimeThread
                    CPUs = 0x1
                    //Note that only the GAMGroup1 has to be scheduled for execution (all the GAMGroup child GAMs will be automatically executed)
                    Functions = {GAMTimer }
                }
            }
        }
        +Run = {
            Class = RealTimeState
            +Threads = {
                Class = ReferenceContainer
                +Thread1 = {
                    Class = RealTimeThread
                    CPUs = 0x1
                    //Note that only the GAMGroup1 has to be scheduled for execution (all the GAMGroup child GAMs will be automatically executed)
                    Functions = {GAMTimer GAMFixed1 GAMGroup1 GAMDisplay}
                }
            }
        }
    }
    +Scheduler = {
        Class = GAMScheduler
        TimingDataSource = Timings
    }
}

Instructions on how to compile and execute the examples can be found here.