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 * @file HttpExample1.cpp
  3 * @brief Source file for class HttpExample1
  4 * @date 26/10/2018
  5 * @author Andre Neto
  6 *
  7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
  8 * the Development of Fusion Energy ('Fusion for Energy').
  9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
 10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
 11 * You may not use this work except in compliance with the Licence.
 12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
 13 *
 14 * @warning Unless required by applicable law or agreed to in writing, 
 15 * software distributed under the Licence is distributed on an "AS IS"
 16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 17 * or implied. See the Licence permissions and limitations under the Licence.
 18
 19 * @details This source file contains the definition of all the methods for
 20 * the class HttpExample1 (public, protected, and private). Be aware that some 
 21 * methods, such as those inline could be defined on the header file, instead.
 22 */
 23#define DLL_API
 24/*---------------------------------------------------------------------------*/
 25/*                         Standard header includes                          */
 26/*---------------------------------------------------------------------------*/
 27#include <math.h>
 28#include <signal.h>
 29
 30/*---------------------------------------------------------------------------*/
 31/*                         Project header includes                           */
 32/*---------------------------------------------------------------------------*/
 33#include "AdvancedErrorManagement.h"
 34#include "BasicConsole.h"
 35#include "ClassRegistryDatabase.h"
 36#include "ClassRegistryItemT.h"
 37#include "ConfigurationDatabase.h"
 38#include "ErrorLoggerExample.h"
 39#include "HighResolutionTimer.h"
 40#include "HttpDataExportI.h"
 41#include "HttpDefinition.h"
 42#include "HttpService.h"
 43#include "Object.h"
 44#include "ObjectRegistryDatabase.h"
 45#include "Reference.h"
 46#include "ReferenceT.h"
 47#include "StandardParser.h"
 48#include "StreamString.h"
 49#include "StructuredDataI.h"
 50
 51/*---------------------------------------------------------------------------*/
 52/*                           Static definitions                              */
 53/*---------------------------------------------------------------------------*/
 54static bool keepRunning = true;
 55static MARTe::float32 timeStepPeriod = 1e-2;
 56static void StopApp(int sig) {
 57    keepRunning = false;
 58}
 59
 60/*---------------------------------------------------------------------------*/
 61/*                           Method definitions                              */
 62/*---------------------------------------------------------------------------*/
 63
 64namespace MARTe2Tutorial {
 65/**
 66 * @brief A MARTe::Object class that will expose its properties using the DataExportI interface.
 67 */
 68class HttpObjectEx1: public MARTe::Object {
 69public:
 70    CLASS_REGISTER_DECLARATION()
 71
 72    /**
 73     * @brief NOOP.
 74     */
 75    HttpObjectEx1() : Object() {
 76        counter = 10u;
 77    }
 78
 79    virtual ~HttpObjectEx1 () {
 80        if (GetName() != NULL_PTR(const MARTe::char8 *)) {
 81            REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
 82                    "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
 83        }
 84    }
 85
 86    virtual bool ExportData(MARTe::StructuredDataI & data) {
 87        bool ok = Object::ExportData(data);
 88        counter++;
 89        if (counter == 30u) {
 90            counter = 10u;
 91        }
 92        if (ok) {
 93            ok = data.Write("Counter", counter);
 94        }
 95        return ok;
 96    }
 97
 98private:
 99    MARTe::uint32 counter;
100
101};
102CLASS_REGISTER(HttpObjectEx1, "1.0")
103
104/**
105 * @brief A MARTe::Object class that will expose its properties using the HttpDataExportI interface.
106 */
107class HttpObjectEx2: public MARTe::Object, public MARTe::HttpDataExportI {
108public:
109    CLASS_REGISTER_DECLARATION()
110
111    /**
112     * @brief NOOP.
113     */
114    HttpObjectEx2() : Object() {
115        counter = 10u;
116    }
117
118    virtual ~HttpObjectEx2 () {
119        if (GetName() != NULL_PTR(const MARTe::char8 *)) {
120            REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
121                    "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
122        }
123    }
124
125    virtual bool GetAsStructuredData(MARTe::StreamStructuredDataI &data, MARTe::HttpProtocol &protocol) {
126        bool ok = HttpDataExportI::GetAsStructuredData(data, protocol);
127        if (ok) {
128            ok = MARTe::Object::ExportData(data);
129        }
130        counter++;
131        if (counter == 30u) {
132            counter = 10u;
133        }
134        if (ok) {
135            ok = data.Write("Counter", counter);
136        }
137        return ok;
138
139    }
140
141    virtual bool GetAsText(MARTe::StreamI &stream, MARTe::HttpProtocol &protocol) {
142        bool ok = HttpDataExportI::GetAsText(stream, protocol);
143        MARTe::StreamString txt;
144        if (ok) {
145            ok = txt.Printf("<html><body><h1>Counter = %d</h1></body></html>\n", counter);
146        }
147        if (ok) {
148            MARTe::uint32 nBytes = txt.Size();
149            ok = stream.Write(txt.Buffer(), nBytes);
150        }
151        return ok;
152    }
153
154private:
155    MARTe::uint32 counter;
156
157};
158CLASS_REGISTER(HttpObjectEx2, "1.0")
159
160
161/**
162 * @brief A MARTe::Object class that will expose its properties using the DataExportI interface.
163 */
164class HttpPendulumEx1: public MARTe::Object {
165public:
166    CLASS_REGISTER_DECLARATION()
167
168    /**
169     * @brief NOOP.
170     */
171    HttpPendulumEx1() : Object() {
172        velocity = 0;
173        angle = 3.1415 / 3;
174        gravity = -9.8;
175        length = 1;
176        timeStepCounter = 0;
177    }
178
179    virtual ~HttpPendulumEx1 () {
180        if (GetName() != NULL_PTR(const MARTe::char8 *)) {
181            REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at %s [%s]. "
182                    "The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
183        }
184    }
185
186    virtual bool ExportData(MARTe::StructuredDataI & data) {
187        bool ok = Object::ExportData(data);
188        if (ok) {
189            ok = data.Write("angle", angle);
190        }
191        return ok;
192    }
193
194    void Execute() {
195        MARTe::float32 acceleration = gravity / length * sinf(angle);
196        velocity += acceleration * timeStepPeriod;
197        angle += velocity * timeStepPeriod;
198        timeStepCounter++;
199        //REPORT_ERROR_STATIC(MARTe::ErrorManagement::Debug, "Time = %f Angle = %f", timeStepPeriod, angle);
200    }
201
202private:
203    MARTe::float32 length;
204    MARTe::float32 velocity;
205    MARTe::float32 angle;
206    MARTe::float32 gravity;
207    MARTe::uint32 timeStepCounter;
208
209};
210CLASS_REGISTER(HttpPendulumEx1, "1.0")
211}
212
213int main(int argc, char **argv) {
214    using namespace MARTe;
215    using namespace MARTe2Tutorial;
216    SetErrorProcessFunction(&ErrorProcessExampleFunction);
217
218    StreamString config = ""
219            "+WebRoot = {"
220            "    Class = HttpObjectBrowser"
221            "    Root = \".\""
222            "    +TheRoot = {"
223            "        Root = \"/\""
224            "        Class = HttpObjectBrowser"
225            "    }"
226            "    +ARootObj1 = {"
227            "        Class = HttpObjectBrowser"
228            "        Root = \".\""
229            "        +AChildObj1 = {"
230            "            Class = HttpObjectEx1"
231            "        }"
232            "        +Obj2 = {"
233            "            Class = HttpObjectEx1"
234            "        }"
235            "    }"
236            "    +ARootObj2 = {"
237            "        Class = HttpObjectEx1"
238            "    }"
239            "    +ARootObj3 = {"
240            "        Class = HttpObjectEx1"
241            "    }"
242            "    +Pendulum = {"
243            "        Class = HttpPendulumEx1"
244            "    }"
245            "    +ResourcesHtml = {"
246            "        Class = HttpDirectoryResource"
247            "        BaseDir = \"../../../../../../Resources/HTTP/\""
248            "    }"
249            "    +ResourcesJS = {"
250            "        Class = HttpDirectoryResource"
251            "        BaseDir = \"../../../../../../Resources/HTTP/JS/\""
252            "    }"
253            "    +ResourcesJS2 = {"
254            "        Class = HttpDirectoryResource"
255            "        BaseDir = \"../Resources/HTTP/\""
256            "    }"
257            "    +ThreadsInformationQuery = {"
258            "        Class = ThreadsInformationQuery"
259            "    }"
260            "}"
261            "+WebServer = {"
262            "    Class = HttpService"
263            "    Port = 8084"
264            "    WebRoot = WebRoot"
265            "    Timeout = 0"
266            "    ListenMaxConnections = 255"
267            "    AcceptTimeout = 1000"
268            "    MaxNumberOfThreads = 64"
269            "    MinNumberOfThreads = 1"
270            "}";
271
272    REPORT_ERROR_STATIC(ErrorManagement::Information, "Loading CFG:\n%s", config.Buffer());
273    ConfigurationDatabase cdb;
274    StreamString err;
275    //Force the string to be seeked to the beginning.
276    config.Seek(0LLU);
277    StandardParser parser(config, cdb, &err);
278    bool ok = parser.Parse();
279    if (ok) {
280        //After parsing the tree is pointing at the last leaf
281        cdb.MoveToRoot();
282        ok = ObjectRegistryDatabase::Instance()->Initialise(cdb);
283    }
284    else {
285        StreamString errPrint;
286        errPrint.Printf("Failed to parse %s", err.Buffer());
287        REPORT_ERROR_STATIC(ErrorManagement::ParametersError, errPrint.Buffer());
288    }
289
290    if (ok) {
291        REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully loaded the configuration file");
292    }
293    ReferenceT<HttpService> service = ObjectRegistryDatabase::Instance()->Find("WebServer");
294    if (ok) {
295        ok = service.IsValid();
296    }
297    if (ok) {
298        ok = service->Start();
299    }
300    StreamString msg = "Type Ctrl + C to exit\n";
301    BasicConsole con;
302    con.Open(BasicConsoleMode::PerformCharacterInput);
303    con.SetSceneSize(64, 1);
304    uint32 msgSize = msg.Size();
305    con.Write(msg.Buffer(), msgSize);
306    ReferenceT<HttpPendulumEx1> pendulum = ObjectRegistryDatabase::Instance()->Find("WebRoot.Pendulum");
307    signal(SIGTERM, StopApp);
308    signal(SIGINT, StopApp);
309    if (ok) {
310        ok = pendulum.IsValid();
311    }
312    if (ok) {
313        while (keepRunning) {
314            pendulum->Execute();
315            Sleep::Sec(timeStepPeriod);
316        }
317    }
318    if (ok) {
319        ok = service->Stop();
320    }
321    return 0;
322}

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 * @file HttpPendulumEx1.js 
 3 * @date 28/03/2019
 4 * @author Andre' Neto
 5 *
 6 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
 7 * the Development of Fusion Energy ('Fusion for Energy').
 8 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
 9 * by the European Commission - subsequent versions of the EUPL (the "Licence")
10 * You may not use this work except in compliance with the Licence.
11 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
12 * Unless required by applicable law or agreed to in writing, 
13 * software distributed under the Licence is distributed on an "AS IS"
14 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
15 * or implied. See the Licence permissions and limitations under the Licence.
16 */
17/**
18 * Default plugin renderer for a pendulum.
19 */
20class HttpPendulumEx1 extends MARTeObject {
21
22    /**
23     * NOOP
24     */
25    constructor() {
26        super();
27        this.pcolor = "yellow";
28    }
29
30
31    /**
32     * Creates the canvas.
33     *
34     * @param {obj} target the target HTML container where to display the data.
35     */
36    prepareDisplay(target) {
37        this.canvas = document.createElement("canvas");
38        this.canvas.setAttribute("class", "pendulumCanvas");
39        this.context = this.canvas.getContext("2d");
40        target.innerHTML = "";
41        target.appendChild(this.canvas);
42        this.refresh(100);
43    }
44
45    /**
46     * Updates the pendulum with the new angle position.
47     *
48     * @param {obj} jsonData the data as received by the server and which should contain the angle.
49     */
50    displayData(jsonData) {
51        var angle = parseFloat(jsonData["angle"]);
52        var width = this.canvas.clientWidth;
53        var height = this.canvas.clientHeight;
54        var length = Math.min(width, height);
55        var rPend = length * 0.4;
56        var rBall = length * 0.04;
57        var rBar = length * 0.004;
58        var ballX = Math.sin(angle) * rPend;
59        var ballY = Math.cos(angle) * rPend;
60        this.context.fillStyle = "white";
61        this.context.fillRect(0, 0, width, height);
62        this.context.save();
63        this.context.translate(width/2, 10);
64        this.context.rotate(angle);
65        this.context.beginPath();
66        this.context.rect(-rBar, -rBar, rBar*2, rPend+rBar*2);
67        this.context.strokeStyle = "black";
68        this.context.fillStyle = "black";
69        this.context.fill();
70        this.context.stroke();
71        this.context.beginPath();
72        this.context.arc(0, rPend, rBall, 0, Math.PI*2, false);
73        this.context.fillStyle = this.pcolor;
74        this.context.fill();
75        this.context.stroke();
76        this.context.restore();
77    }
78
79    /**
80     * Sets the pendulum color.
81     *
82     * @param {color} c the new pendulum color.
83     */
84    setColor(c) {
85        this.pcolor = c;
86    }
87}

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+WebRoot = {
  2    Class = HttpObjectBrowser
  3    Root = "."
  4    +ObjectBrowse = {
  5        Class = HttpObjectBrowser
  6        Root = "/"
  7    }
  8    +ResourcesHtml = {
  9        Class = HttpDirectoryResource
 10        BaseDir = "../../../../../Resources/HTTP/"
 11    }    
 12    +HttpMessageInterface = {
 13        Class = HttpMessageInterface
 14        +GOTOIDLE = {
 15            Class = Message
 16            Destination = StateMachine
 17            Function = GOTOIDLE
 18            Mode = ExpectsReply
 19        }
 20        +GOTORUN = {
 21            Class = Message
 22            Destination = StateMachine
 23            Function = GOTORUN
 24            Mode = ExpectsReply
 25        }
 26        +GOTOERR = {
 27            Class = Message
 28            Destination = StateMachineError
 29            Function = GOTOERR 
 30            Mode = ExpectsReply
 31        }
 32    }
 33}
 34+WebServer = {
 35    Class = HttpService
 36    Port = 8084
 37    WebRoot = WebRoot
 38    Timeout = 0
 39    ListenMaxConnections = 255
 40    AcceptTimeout = 1000
 41    MaxNumberOfThreads = 8
 42    MinNumberOfThreads = 1
 43}
 44+StateMachine = {
 45    Class = StateMachine
 46    +INITIAL = {
 47        Class = ReferenceContainer      
 48        +START = {
 49            Class = StateMachineEvent
 50            NextState = "IDLE"
 51            NextStateError = "IDLE"
 52            Timeout = 0
 53            +StartHttpServer = {
 54                Class = Message
 55                Destination = "WebServer"
 56                Function = "Start"
 57                Mode = ExpectsReply
 58            }            
 59            +ChangeToStateIdleMsg = {
 60                Class = Message
 61                Destination = TestApp
 62                Mode = ExpectsReply
 63                Function = PrepareNextState
 64                +Parameters = {
 65                    Class = ConfigurationDatabase
 66                    param1 = Idle
 67                }
 68            }
 69            +StartNextStateExecutionMsg = {
 70                Class = Message
 71                Destination = TestApp
 72                Function = StartNextStateExecution
 73                Mode = ExpectsReply
 74            }
 75        }
 76    }
 77    +IDLE = {
 78        Class = ReferenceContainer
 79        +GOTORUN = {
 80            Class = StateMachineEvent
 81            NextState = "RUN"
 82            NextStateError = "IDLE"
 83            Timeout = 0 
 84            +ChangeToRunMsg = {
 85                Class = Message
 86                Destination = TestApp
 87                Mode = ExpectsReply
 88                Function = PrepareNextState
 89                +Parameters = {
 90                    Class = ConfigurationDatabase
 91                    param1 = Run
 92                }
 93            }
 94            +StopCurrentStateExecutionMsg = {
 95                Class = Message
 96                Destination = TestApp
 97                Function = StopCurrentStateExecution
 98                Mode = ExpectsReply
 99            }
100            +StartNextStateExecutionMsg = {
101                Class = Message
102                Destination = TestApp
103                Function = StartNextStateExecution
104                Mode = ExpectsReply
105            }
106        }
107    }
108    +RUN = {
109        Class = ReferenceContainer
110        +GOTOIDLE = {
111            Class = StateMachineEvent
112            NextState = "IDLE"
113            NextStateError = "IDLE"
114            Timeout = 0         
115            +ChangeToIdleMsg = {
116                Class = Message
117                Destination = TestApp
118                Mode = ExpectsReply
119                Function = PrepareNextState
120                +Parameters = {
121                    Class = ConfigurationDatabase
122                    param1 = Idle
123                }
124            }
125            +StopCurrentStateExecutionMsg = {
126                Class = Message
127                Destination = TestApp
128                Function = StopCurrentStateExecution
129                Mode = ExpectsReply
130            }
131            +StartNextStateExecutionMsg = {
132                Class = Message
133                Destination = TestApp
134                Function = StartNextStateExecution
135                Mode = ExpectsReply
136            }
137        }   
138    }
139}
140$TestApp = {
141    Class = RealTimeApplication
142    +Functions = {
143        Class = ReferenceContainer
144        +GAMTimer = {
145            Class = IOGAM
146            InputSignals = {
147                Counter = {
148                    DataSource = Timer
149                    Type = uint32
150                }
151                Time = {
152                    Frequency = 1
153                    DataSource = Timer
154                    Type = uint32
155                }
156            }
157            OutputSignals = {
158                Counter = {
159                    DataSource = DDB1
160                    Type = uint32
161                }
162                Time = {
163                    DataSource = DDB1
164                    Type = uint32
165                }
166            }
167        }
168        +GAMFixed1 = {
169            Class = FixedGAMExample1
170            Gain = 2
171            InputSignals = {
172                Counter = {
173                    DataSource = DDB1
174                    Type = uint32
175                }
176            }
177            OutputSignals = {
178                GainCounter = {
179                    DataSource = DDB1
180                    Type = uint32
181                }
182            }
183        }
184        +GAMGroup1 = {
185            Class = ParentGAMGroupExample1
186            Model = {{2, 0, 0}, {0, 3, 0}, {1, 0, 4}}
187            +GAMChild1 = {
188                Class = ChildGAMGroupExample1
189                InputSignals = {
190                    Signal3 = {
191                        DataSource = DDB1
192                        Type = uint32
193                        NumberOfDimensions = 1
194                        NumberOfElements = 3
195                    }
196                }
197                OutputSignals = {
198                    Signal1 = {
199                        DataSource = DDB1
200                        Type = uint32
201                        NumberOfDimensions = 1 
202                        NumberOfElements = 3
203                        Default = {1, 1, 1}
204                    }
205                 }
206            } 
207            +GAMChild2 = {
208                Class = ChildGAMGroupExample2
209                InputSignals = {
210                    Signal1 = {
211                        DataSource = DDB1
212                        Type = uint32
213                        NumberOfDimensions = 1
214                        NumberOfElements = 3
215                    }
216                }
217                OutputSignals = {
218                    Signal2 = {
219                        DataSource = DDB1
220                        Type = uint32
221                        NumberOfDimensions = 1 
222                        NumberOfElements = 3
223                        Default = {1, 1, 1}
224                    }
225                 }
226            }
227            +GAMChild3 = {
228                Class = ChildGAMGroupExample1
229                InputSignals = {
230                    Signal2 = {
231                        DataSource = DDB1
232                        Type = uint32
233                        NumberOfDimensions = 1 
234                        NumberOfElements = 3
235                    }
236                }
237                OutputSignals = {
238                    Signal3 = {
239                        DataSource = DDB1
240                        Type = uint32
241                        NumberOfDimensions = 1 
242                        NumberOfElements = 3
243                        Default = {1, 1, 1}
244                    }
245                }
246             }
247        }
248        +GAMDisplay = {
249            Class = IOGAM
250            InputSignals = {
251                Counter = {
252                    DataSource = DDB1
253                    Type = uint32
254                    Default = 100
255                }
256                GainCounter = {
257                    DataSource = DDB1
258                    Type = uint32
259                }
260                Signal1 = {
261                    DataSource = DDB1
262                    Type = uint32
263                }
264                Signal2 = {
265                    DataSource = DDB1
266                    Type = uint32
267                }
268                //Print only the first and the last element of Signal 3
269                Signal3 = {
270                    DataSource = DDB1
271                    Type = uint32
272                    Ranges = {{0,0}, {2, 2}}
273                    NumberOfElements = 3
274                    NumberOfDimensions = 1
275                }
276            }
277            OutputSignals = {
278                Counter = {
279                    DataSource = LoggerDataSource
280                    Type = uint32
281                }
282                GainCounter = {
283                    DataSource = LoggerDataSource
284                    Type = uint32
285                } 
286                Signal1 = {
287                    DataSource = LoggerDataSource
288                    Type = uint32
289                    NumberOfElements = 3
290                    NumberOfDimensions = 1
291                }              
292                Signal2 = {
293                    DataSource = LoggerDataSource
294                    Type = uint32
295                    NumberOfElements = 3
296                    NumberOfDimensions = 1
297                }
298                Signal3FirstAndLast = {
299                    DataSource = LoggerDataSource
300                    Type = uint32
301                    NumberOfElements = 2
302                    NumberOfDimensions = 1
303                }
304            }
305        }
306    }
307    +Data = {
308        Class = ReferenceContainer
309        DefaultDataSource = DDB1
310        +DDB1 = {
311            Class = GAMDataSource
312        }        
313        +LoggerDataSource = {
314            Class = LoggerDataSource
315        }
316        +Timings = {
317            Class = TimingDataSource
318        }
319        +Timer = {
320            Class = LinuxTimer
321            SleepNature = "Default"
322            Signals = {
323                Counter = {
324                    Type = uint32
325                }
326                Time = {
327                    Type = uint32
328                }
329            }
330        }
331    }
332    +States = {
333        Class = ReferenceContainer
334        +Idle = {
335            Class = RealTimeState
336            +Threads = {
337                Class = ReferenceContainer
338                +Thread1 = {
339                    Class = RealTimeThread
340                    CPUs = 0x1
341                    //Note that only the GAMGroup1 has to be scheduled for execution (all the GAMGroup child GAMs will be automatically executed)
342                    Functions = {GAMTimer }
343                }
344            }
345        }
346        +Run = {
347            Class = RealTimeState
348            +Threads = {
349                Class = ReferenceContainer
350                +Thread1 = {
351                    Class = RealTimeThread
352                    CPUs = 0x1
353                    //Note that only the GAMGroup1 has to be scheduled for execution (all the GAMGroup child GAMs will be automatically executed)
354                    Functions = {GAMTimer GAMFixed1 GAMGroup1 GAMDisplay}
355                }
356            }
357        }
358    }
359    +Scheduler = {
360        Class = GAMScheduler
361        TimingDataSource = Timings
362    }
363}

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