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/
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:
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.
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.