RealTimeApplication¶
A MARTe RealTimeApplication is assembled by connecting together GAMs and DataSources.
GAMs are grouped in real-time threads which are executed in the context of specific states. A RealTimeApplication shall be in one (and only one) given state at any given time.
The orchestration of the states is performed by means of messages (e.g. by a component that relays HTTP requests into MARTe messages).

Configuration¶
The configuration of a RealTimeApplication has to follow a set of strict rules.
In particular, the nodes Functions
, Data
, States
and Scheduler
shall exist and shall be configured using the rules defined below:
Functions¶
GAMs are listed inside a node named Functions
of type ReferenceContainer
.
$App1 = {
Class = RealTimeApplication
+Functions = {
Class = ReferenceContainer
+GAM1 = {
Class = AGAM
InputSignals = {
...
}
OutputSignals = {
...
}
}
+GAM2 = {
Class = BGAM
InputSignals = {
...
}
OutputSignals = {
...
}
}
...
}
...
}
GAMs can also be grouped inside reference containers (in order to improve the readability of a configuration stream) and inside GAMGroups.
$App1 = {
Class = RealTimeApplication
+Functions = {
Class = ReferenceContainer
+Controllers = {
Class = ReferenceContainer
+PID1 = {
Class = PIDGAM
InputSignals = {
...
}
OutputSignals = {
...
}
}
+PID2 = {
Class = PIDGAM
InputSignals = {
...
}
OutputSignals = {
...
}
}
}
+GAM2 = {
Class = GAMGroup
+GAM3 = {
InputSignals = {
...
}
OutputSignals = {
...
}
}
+GAM4 = {
InputSignals = {
...
}
OutputSignals = {
...
}
}
...
}
...
}
Data¶
DataSources are grouped inside a node named Data
of type ReferenceContainer
.
$App1 = {
Class = RealTimeApplication
+Functions = {
Class = ReferenceContainer
...
}
+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
}
}
}
...
...
}
A component of class type TimingDataSource
shall exist.
The property DefaultDataSource
shall define what is the DataSource to be used when the GAM signals do not specify the DataSource
property.
TimingDataSource¶
The RealTimeApplication will automatically add to the TimingDataSource the following signals:
For every RealTimeThread, it will generate a signal named
STATE_NAME.THREAD_NAME_CycleTime
, whereSTATE_NAME
is the name of the state where the thread is running andTHREAD_NAME
is the name of the RealTimeThread object instance. The type of this signal is uint32 and it holds the thread cycle time.- For every GAM, it will generate three signals named:
GAM_NAME_ReadTime
,GAM_NAME_WriteTime
andGAM_NAME_ExecTime
where GAM_NAME` is the object name of the GAM instance. The type of these signals is uint32. The
GAM_NAME_ReadTime
holds the time elapsed from the beginning of the cycle until all the input brokers for thisGAM_NAME
have been executed;The
GAM_NAME_WriteTime
holds the time elapsed from the beginning of the cycle until all the output brokers for thisGAM_NAME
have been executed;The
GAM_NAME_ExecTime
holds the time elapsed from the beginning of the cycle until thisGAM_NAME
has finished its execution.
- For every GAM, it will generate three signals named:
$App1 = {
Class = RealTimeApplication
+Functions = {
Class = ReferenceContainer
+GAMDisplay = {
Class = IOGAM
InputSignals = {
State1_Thread1_CycleTime = {
Alias = State1.Thread1_CycleTime
DataSource = Timings
Type = uint32
}
GAMFixed1_ReadTime = {
DataSource = Timings
Type = uint32
}
GAMFixed1_ExecTime = {
DataSource = Timings
Type = uint32
}
GAMFixed1_WriteTime = {
DataSource = Timings
Type = uint32
}
...
}
...
}
...
}
+Data = {
Class = ReferenceContainer
DefaultDataSource = DDB1
...
+Timings = {
Class = TimingDataSource
}
...
Warning
Given that a MARTe object name may not contain a .
and given that the cycle time signal produced by the Timings DataSource is named STATE_NAME.THREAD_NAME_CycleTime
, an Alias will always have to be used to read the signal.
InputSignals = {
State1_Thread1_CycleTime = {
Alias = State1.Thread1_CycleTime
DataSource = Timings
States¶
The available RealTimeApplication states are listed inside a node named States
of type RealTimeState.
Each state shall have a node named Threads
with the list of RealTimeThread components to be executed in that state.
Each RealTimeThread shall contain the name of the Functions
to be executed. Note that if the function is a ReferenceContainer or a GAMGroup, the GAMs contained inside these containers shall not be declared (as they are automatically added for scheduling).
$App1 = {
Class = RealTimeApplication
+Functions = {
Class = ReferenceContainer
+Controllers1 = {
Class = ReferenceContainer
+PID1 = {
...
}
+PID2 = {
...
}
}
+Controllers2 = {
Class = ReferenceContainer
+PID3 = {
...
}
+PID4 = {
...
}
}
+GAMGroup1 = {
Class = GAMGroup
+GAM3 = {
...
}
+GAM4 = {
...
}
...
}
+Reference1 = {
Class = AGAM
...
}
+Reference2 = {
Class = AGAM
...
}
}
+States = {
Class = ReferenceContainer
+State1 = {
Class = RealTimeState
+Threads = {
Class = ReferenceContainer
+Thread1 = {
Class = RealTimeThread
CPUs = 0x1 //Only meaningful in operating systems that support it
Functions = {Reference1 Controllers1 GAMGroup1} // Note that PID1 and PID2, etc are implicitly called.
}
+Thread2 = {
Class = RealTimeThread
CPUs = 0x2 //Only meaningful in operating systems that support it
Functions = {Reference2 Controllers2}
}
}
}
+State2 = {
Class = RealTimeState
+Threads = {
Class = ReferenceContainer
+Thread1 = {
Class = RealTimeThread
Functions = {Reference1 GAMGroup1 }
}
}
Scheduler¶
The scheduler is defined in a node named Scheduler
and the class shall inherit from GAMSchedulerI.
The name of the node containing the TimingDataSource class shall be defined in a parameter named TimingDataSource
.
$App1 = {
Class = RealTimeApplication
...
+Scheduler = {
Class = GAMScheduler
TimingDataSource = Timings
}
The framework offers a multi-thread scheduler (see GAMScheduler). Bare metal applications will typically develop bespoke scheduling mechanisms.
Initialisation¶
A RealTimeApplication is initialised just like any other MARTe Object. Internally, the RealTimeApplication initialisation is mostly delegated to the RealTimeApplicationBuilder component and is divided in two stages: first all the signals dependencies, between the GAMs and the DataSources, are completed and verified (see Rules below). This is followed by a stage where the Brokers are instantiated and all the required memory allocated.
The two states are independent and can be performed in separate phases. This allows, for example, to pre-compute (see RealTimeApplicationBuilder::ConfigureBeforeInitialisation
) and directly store in the memory of a low-power embedded system the output of the signal verification logic (phase 1 of the initialisation).
The RealTimeApplication will try to complete the missing signal properties based on the information that is available. If a GAM requires a signal that is produced by a subsequent GAM, an implicit zero-hold is introduced in the cycle and the signal is initialised to its Default value.

Rules¶
The following rules have to be met and are verified by the RealTimeApplication
initialisation mechanism:
Global rules¶
The nodes
Functions
,Data
,States
andScheduler
shall exist;At least one GAM shall be declared;
At least one DataSource shall be declared;
Exactly one TimingDataSource shall be declared;
At least one state shall be declared;
For each state, at least one thread shall be declared;
For each thread, at least one function (GAM) shall be declared;
Signal rules¶
For every thread, the input port of each GAM or DataSource shall be connected to exactly one signal (from another GAM or from a DataSource);
For every thread, the output port of a given GAM or DataSource may be connected to zero or more signals (in another GAM or DataSource);
The properties (type, number of elements and number of dimensions) of each signal shall be fully consistent between the signal producer and the signal consumer;
The signal type shall be defined either by the signal producer or by one of the signal consumers:
If the number of elements is not defined, one is assumed;
the number of dimensions is not defined, zero is assumed (scalar signal);
If no Default value is specified, zero is assumed.
For every thread, at most one signal shall define the property Frequency (i.e. at most one synchronisation point per thread).
The following is a valid example where the GAM resolves the signal type from the DataSource.

In this example the type of the signal A1 is not defined by the producer nor by the source and thus the configuration is invalid and will fail.

In the following, there is a contradiction between the properties of the signal A1 and thus the configuration will also fail.

The correct way to access an array of smaller dimensions is to use the parameter Ranges
. The GAM parameter will only use (and allocate memory) to the first two elements of the array:

State change¶
The state can be changed by calling the methods PrepareNextState
, StopCurrentStateExecution
and StartNextStateExecution
on the RealTimeApplication.
These are methods are registered as RPC functions and thus can be triggered using the messaging mechanisms.
Typically the interface to the state changing mechanism is provided by the StateMachine.

+StateMachine = {
Class = StateMachine
...
+STATE1 = {
Class = ReferenceContainer
+GOTOSTATE2 = {
Class = StateMachineEvent
NextState = "STATE2"
NextStateError = "ERROR"
Timeout = 0
+PrepareChangeToState2Msg = {
Class = Message
Destination = TestApp
Mode = ExpectsReply
Function = PrepareNextState
+Parameters = {
Class = ConfigurationDatabase
param1 = State2
}
}
+StopCurrentStateExecutionMsg = {
Class = Message
Destination = TestApp
Function = StopCurrentStateExecution
Mode = ExpectsReply
}
+StartNextStateExecutionMsg = {
Class = Message
Destination = TestApp
Function = StartNextStateExecution
Mode = ExpectsReply
}
...
Synchronising multiple threads¶
The synchronisation between threads is performed using the RealTimeThreadSynchronisation DataSource component.

The threads synchronising can run at a frequency which is sub-multiple of the master (i.e. the one with the GAM writing to the DataSource) thread frequency . This is expressed by asking for a number of samples (> 1) to the RealTimeThreadSynchronisation DataSource.
The RealTimeThreadAsyncBridge component also allows to exchange data between threads without an explicit synchronisation point. This means that the consumer threads will use the latest available data.
Examples¶
GAMGroup and Ranges¶
In the RealTimeApplication example below, note that only the name of the parent GAMGroup has to be set for scheduling (as opposed to individually listing all of its internal GAM members).
Note also how the Ranges
can be used to only access a subset of an array.
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 | $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
}
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
+State1 = {
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
}
}
|
Execution times¶

The following is an example of a RealTimeApplication which prints the execution times of the real-time thread and of the GAMs (including the brokers’ read/write times).
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 | $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
}
}
}
+GAMDisplay = {
Class = IOGAM
InputSignals = {
Counter = {
DataSource = DDB1
Type = uint32
}
GainCounter = {
DataSource = DDB1
Type = uint32
}
State1_Thread1_CycleTime = {
Alias = State1.Thread1_CycleTime
DataSource = Timings
Type = uint32
}
GAMTimer_ReadTime = {
DataSource = Timings
Type = uint32
}
GAMTimer_ExecTime = {
DataSource = Timings
Type = uint32
}
GAMTimer_WriteTime = {
DataSource = Timings
Type = uint32
}
GAMFixed1_ReadTime = {
DataSource = Timings
Type = uint32
}
GAMFixed1_ExecTime = {
DataSource = Timings
Type = uint32
}
GAMFixed1_WriteTime = {
DataSource = Timings
Type = uint32
}
}
OutputSignals = {
Counter = {
DataSource = LoggerDataSource
Type = uint32
}
GainCounter = {
DataSource = LoggerDataSource
Type = uint32
}
State1_Thread1_CycleTime = {
DataSource = LoggerDataSource
Type = uint32
}
GAMTimer_ReadTime = {
DataSource = LoggerDataSource
Type = uint32
}
GAMTimer_ExecTime = {
DataSource = LoggerDataSource
Type = uint32
}
GAMTimer_WriteTime = {
DataSource = LoggerDataSource
Type = uint32
}
GAMFixed1_ReadTime = {
DataSource = LoggerDataSource
Type = uint32
}
GAMFixed1_ExecTime = {
DataSource = LoggerDataSource
Type = uint32
}
GAMFixed1_WriteTime = {
DataSource = LoggerDataSource
Type = uint32
}
}
}
}
+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
+State1 = {
Class = RealTimeState
+Threads = {
Class = ReferenceContainer
+Thread1 = {
Class = RealTimeThread
CPUs = 0x1
Functions = {GAMTimer GAMFixed1 GAMDisplay }
}
}
}
}
+Scheduler = {
Class = GAMScheduler
TimingDataSource = Timings
}
}
|
Multiple states¶

This is an example of a RealTimeApplication with two states. The custom component TCPSocketMessageProxyExample
forwards TCP messages into MARTe messages.
Start the application with the -m parameter.
In order to change state, start the application and, in another console, type echo -e "Destination=StateMachine\nFunction=GOTOSTATE2" | nc 127.0.0.1 24680
.
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 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 | +TCPMessageProxy = {
Class = TCPSocketMessageProxyExample
Port = 24680
}
+StateMachine = {
Class = StateMachine
+INITIAL = {
Class = ReferenceContainer
+START = {
Class = StateMachineEvent
NextState = "STATE1"
NextStateError = "ERROR"
Timeout = 0
+ChangeToState1Msg = {
Class = Message
Destination = TestApp
Mode = ExpectsReply
Function = PrepareNextState
+Parameters = {
Class = ConfigurationDatabase
param1 = State1
}
}
+StartNextStateExecutionMsg = {
Class = Message
Destination = TestApp
Function = StartNextStateExecution
Mode = ExpectsReply
}
}
}
+STATE1 = {
Class = ReferenceContainer
+GOTOSTATE2 = {
Class = StateMachineEvent
NextState = "STATE2"
NextStateError = "ERROR"
Timeout = 0
+PrepareChangeToState2Msg = {
Class = Message
Destination = TestApp
Mode = ExpectsReply
Function = PrepareNextState
+Parameters = {
Class = ConfigurationDatabase
param1 = State2
}
}
+StopCurrentStateExecutionMsg = {
Class = Message
Destination = TestApp
Function = StopCurrentStateExecution
Mode = ExpectsReply
}
+StartNextStateExecutionMsg = {
Class = Message
Destination = TestApp
Function = StartNextStateExecution
Mode = ExpectsReply
}
}
+ERROR = {
Class = StateMachineEvent
NextState = "ERROR"
NextStateError = "ERROR"
}
}
+STATE2 = {
Class = ReferenceContainer
+GOTOSTATE1 = {
Class = StateMachineEvent
NextState = "STATE1"
NextStateError = "ERROR"
Timeout = 0
+PrepareChangeToState1Msg = {
Class = Message
Destination = TestApp
Mode = ExpectsReply
Function = PrepareNextState
+Parameters = {
Class = ConfigurationDatabase
param1 = State1
}
}
+StopCurrentStateExecutionMsg = {
Class = Message
Destination = TestApp
Function = StopCurrentStateExecution
Mode = ExpectsReply
}
+StartNextStateExecutionMsg = {
Class = Message
Destination = TestApp
Function = StartNextStateExecution
Mode = ExpectsReply
}
}
+ERROR = {
Class = StateMachineEvent
NextState = "ERROR"
NextStateError = "ERROR"
}
}
+ERROR = {
Class = ReferenceContainer
+ENTER = {
Class = ReferenceContainer
+StopCurrentStateExecutionMsg = {
Class = Message
Destination = TestApp
Function = StopCurrentStateExecution
Mode = ExpectsReply
}
+PrepareChangeToErrorMsg = {
Class = Message
Destination = TestApp
Mode = ExpectsReply
Function = PrepareNextState
+Parameters = {
Class = ConfigurationDatabase
param1 = StateError
}
}
+StartNextStateExecutionMsg = {
Class = Message
Destination = TestApp
Function = StartNextStateExecution
Mode = ExpectsReply
}
}
+RESET = {
Class = StateMachineEvent
NextState = "STATE1"
NextStateError = "STATE1"
Timeout = 0
+StopCurrentStateExecutionMsg = {
Class = Message
Destination = TestApp
Function = StopCurrentStateExecution
Mode = ExpectsReply
}
+PrepareChangeToState1Msg = {
Class = Message
Destination = TestApp
Mode = ExpectsReply
Function = PrepareNextState
+Parameters = {
Class = ConfigurationDatabase
param1 = State1
}
}
+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
}
}
}
+GAMVariable1 = {
Class = VariableGAMExample1
Gains = {2, 3, 4}
InputSignals = {
Counter = {
DataSource = DDB1
Type = uint32
}
}
OutputSignals = {
GainCounter1Thread1 = {
DataSource = DDB1
Type = uint32
}
GainCounter2Thread1 = {
DataSource = DDB1
Type = uint32
}
GainCounter3Thread1 = {
DataSource = DDB1
Type = uint32
}
}
}
+GAMT1TSynchOut = {
Class = IOGAM
InputSignals = {
GainCounter1Thread1 = {
DataSource = DDB1
Type = uint32
}
GainCounter2Thread1 = {
DataSource = DDB1
Type = uint32
}
GainCounter3Thread1 = {
DataSource = DDB1
Type = uint32
}
}
OutputSignals = {
GainCounter1Thread1 = {
DataSource = RTThreadSynch
Type = uint32
}
GainCounter2Thread1 = {
DataSource = RTThreadSynch
Type = uint32
}
GainCounter3Thread1 = {
DataSource = RTThreadSynch
Type = uint32
}
}
}
+GAMT1T2Interface = {
Class = IOGAM
InputSignals = {
GainCounter1Thread1 = {
DataSource = RTThreadSynch
Type = uint32
Samples = 2 //Run at half the frequency of thread 1
}
GainCounter2Thread1 = {
DataSource = RTThreadSynch
Type = uint32
Samples = 2 //Run at half the frequency of thread 1
}
GainCounter3Thread1 = {
DataSource = RTThreadSynch
Type = uint32
Samples = 2 //Run at half the frequency of thread 1
}
}
OutputSignals = {
GainCounter1Thread2 = {
DataSource = DDB1
Type = uint32
Samples = 1
NumberOfDimensions = 1
NumberOfElements = 2 //2 elements for each cycle (as it waits for 2 samples)
}
GainCounter2Thread2 = {
DataSource = DDB1
Type = uint32
Samples = 1
NumberOfDimensions = 1
NumberOfElements = 2 //2 elements for each cycle (as it waits for 2 samples)
}
GainCounter3Thread2 = {
DataSource = DDB1
Type = uint32
Samples = 1
NumberOfDimensions = 1
NumberOfElements = 2 //2 elements for each cycle (as it waits for 2 samples)
}
}
}
+GAMT1T3Interface = {
Class = IOGAM
InputSignals = {
GainCounter1Thread1 = {
DataSource = RTThreadSynch
Type = uint32
Samples = 4 //Run at one quarter of the frequency of thread 1
}
GainCounter2Thread1 = {
DataSource = RTThreadSynch
Type = uint32
Samples = 4 //Run at one quarter the frequency of thread 1
}
GainCounter3Thread1 = {
DataSource = RTThreadSynch
Type = uint32
Samples = 4 //Run at one quarter the frequency of thread 1
}
}
OutputSignals = {
GainCounter1Thread3 = {
DataSource = DDB1
Type = uint32
Samples = 1
NumberOfDimensions = 1
NumberOfElements = 4 //4 elements for each cycle (as it waits for 4 samples)
}
GainCounter2Thread3 = {
DataSource = DDB1
Type = uint32
Samples = 1
NumberOfDimensions = 1
NumberOfElements = 4 //4 elements for each cycle (as it waits for 4 samples)
}
GainCounter3Thread3 = {
DataSource = DDB1
Type = uint32
Samples = 1
NumberOfDimensions = 1
NumberOfElements = 4 //4 elements for each cycle (as it waits for 4 samples)
}
}
}
+GAMDisplayThread1 = {
Class = IOGAM
InputSignals = {
Counter = {
DataSource = DDB1
Type = uint32
}
GainCounter1Thread1 = {
DataSource = DDB1
Type = uint32
}
GainCounter2Thread1 = {
DataSource = DDB1
Type = uint32
}
GainCounter3Thread1 = {
DataSource = DDB1
Type = uint32
}
}
OutputSignals = {
Counter = {
DataSource = LoggerDataSource
Type = uint32
}
GainCounter1Thread1 = {
DataSource = LoggerDataSource
Type = uint32
}
GainCounter2Thread1 = {
DataSource = LoggerDataSource
Type = uint32
}
GainCounter3Thread1 = {
DataSource = LoggerDataSource
Type = uint32
}
}
}
+GAMDisplayThread2 = {
Class = IOGAM
InputSignals = {
GainCounter1Thread2 = {
DataSource = DDB1
Type = uint32
}
GainCounter2Thread2 = {
DataSource = DDB1
Type = uint32
}
GainCounter3Thread2 = {
DataSource = DDB1
Type = uint32
}
}
OutputSignals = {
GainCounter1Thread2 = {
DataSource = LoggerDataSource
Type = uint32
NumberOfDimensions = 1
NumberOfElements = 2
}
GainCounter2Thread2 = {
DataSource = LoggerDataSource
Type = uint32
NumberOfDimensions = 1
NumberOfElements = 2
}
GainCounter3Thread2 = {
DataSource = LoggerDataSource
Type = uint32
NumberOfDimensions = 1
NumberOfElements = 2
}
}
}
+GAMDisplayThread3 = {
Class = IOGAM
InputSignals = {
GainCounter1Thread3 = {
DataSource = DDB1
Type = uint32
}
GainCounter2Thread3 = {
DataSource = DDB1
Type = uint32
}
GainCounter3Thread3 = {
DataSource = DDB1
Type = uint32
}
}
OutputSignals = {
GainCounter1Thread3 = {
DataSource = LoggerDataSource
Type = uint32
NumberOfDimensions = 1
NumberOfElements = 4
}
GainCounter2Thread3 = {
DataSource = LoggerDataSource
Type = uint32
NumberOfDimensions = 1
NumberOfElements = 4
}
GainCounter3Thread3 = {
DataSource = LoggerDataSource
Type = uint32
NumberOfDimensions = 1
NumberOfElements = 4
}
}
}
}
+Data = {
Class = ReferenceContainer
DefaultDataSource = DDB1
+DDB1 = {
Class = GAMDataSource
}
+LoggerDataSource = {
Class = LoggerDataSource
}
+Timings = {
Class = TimingDataSource
}
+RTThreadSynch = {
Class = RealTimeThreadSynchronisation
Timeout = 5000 //Timeout in ms to wait for the thread to cycle.
}
+Timer = {
Class = LinuxTimer
SleepNature = "Default"
Signals = {
Counter = {
Type = uint32
}
Time = {
Type = uint32
}
}
}
}
+States = {
Class = ReferenceContainer
+State1 = {
Class = RealTimeState
+Threads = {
Class = ReferenceContainer
+Thread1 = {
Class = RealTimeThread
CPUs = 0x1
Functions = {GAMTimer GAMVariable1 GAMT1TSynchOut GAMDisplayThread1}
}
}
}
+State2 = {
Class = RealTimeState
+Threads = {
Class = ReferenceContainer
+Thread1 = {
Class = RealTimeThread
CPUs = 0x1
Functions = {GAMTimer GAMVariable1 GAMT1TSynchOut GAMDisplayThread1}
}
+Thread2 = {
Class = RealTimeThread
CPUs = 0x2
Functions = {GAMT1T2Interface GAMDisplayThread2}
}
+Thread3 = {
Class = RealTimeThread
CPUs = 0x4
Functions = {GAMT1T3Interface GAMDisplayThread3}
}
}
}
+StateError = {
Class = RealTimeState
+Threads = {
Class = ReferenceContainer
+Thread1 = {
Class = RealTimeThread
CPUs = 0x1
Functions = {GAMTimer}
}
}
}
}
+Scheduler = {
Class = GAMScheduler
TimingDataSource = Timings
}
}
|
Thread Synchronisation¶
The following is an example of a RealTimeApplication with multiple synchronised threads. Note that the Thread2 and the Thread3 run at a sub-frequency of Thread1.

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 | $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
}
}
}
+GAMVariable1 = {
Class = VariableGAMExample1
Gains = {2, 3, 4}
InputSignals = {
Counter = {
DataSource = DDB1
Type = uint32
}
}
OutputSignals = {
GainCounter1Thread1 = {
DataSource = DDB1
Type = uint32
}
GainCounter2Thread1 = {
DataSource = DDB1
Type = uint32
}
GainCounter3Thread1 = {
DataSource = DDB1
Type = uint32
}
}
}
+GAMT1TSynchOut = {
Class = IOGAM
InputSignals = {
GainCounter1Thread1 = {
DataSource = DDB1
Type = uint32
}
GainCounter2Thread1 = {
DataSource = DDB1
Type = uint32
}
GainCounter3Thread1 = {
DataSource = DDB1
Type = uint32
}
}
OutputSignals = {
GainCounter1Thread1 = {
DataSource = RTThreadSynch
Type = uint32
}
GainCounter2Thread1 = {
DataSource = RTThreadSynch
Type = uint32
}
GainCounter3Thread1 = {
DataSource = RTThreadSynch
Type = uint32
}
}
}
+GAMT1T2Interface = {
Class = IOGAM
InputSignals = {
GainCounter1Thread1 = {
DataSource = RTThreadSynch
Type = uint32
Samples = 2 //Run at half the frequency of thread 1
}
GainCounter2Thread1 = {
DataSource = RTThreadSynch
Type = uint32
Samples = 2 //Run at half the frequency of thread 1
}
GainCounter3Thread1 = {
DataSource = RTThreadSynch
Type = uint32
Samples = 2 //Run at half the frequency of thread 1
}
}
OutputSignals = {
GainCounter1Thread2 = {
DataSource = DDB1
Type = uint32
Samples = 1
NumberOfDimensions = 1
NumberOfElements = 2 //2 elements for each cycle (as it waits for 2 samples)
}
GainCounter2Thread2 = {
DataSource = DDB1
Type = uint32
Samples = 1
NumberOfDimensions = 1
NumberOfElements = 2 //2 elements for each cycle (as it waits for 2 samples)
}
GainCounter3Thread2 = {
DataSource = DDB1
Type = uint32
Samples = 1
NumberOfDimensions = 1
NumberOfElements = 2 //2 elements for each cycle (as it waits for 2 samples)
}
}
}
+GAMT1T3Interface = {
Class = IOGAM
InputSignals = {
GainCounter1Thread1 = {
DataSource = RTThreadSynch
Type = uint32
Samples = 4 //Run at one quarter of the frequency of thread 1
}
GainCounter2Thread1 = {
DataSource = RTThreadSynch
Type = uint32
Samples = 4 //Run at one quarter the frequency of thread 1
}
GainCounter3Thread1 = {
DataSource = RTThreadSynch
Type = uint32
Samples = 4 //Run at one quarter the frequency of thread 1
}
}
OutputSignals = {
GainCounter1Thread3 = {
DataSource = DDB1
Type = uint32
Samples = 1
NumberOfDimensions = 1
NumberOfElements = 4 //4 elements for each cycle (as it waits for 4 samples)
}
GainCounter2Thread3 = {
DataSource = DDB1
Type = uint32
Samples = 1
NumberOfDimensions = 1
NumberOfElements = 4 //4 elements for each cycle (as it waits for 4 samples)
}
GainCounter3Thread3 = {
DataSource = DDB1
Type = uint32
Samples = 1
NumberOfDimensions = 1
NumberOfElements = 4 //4 elements for each cycle (as it waits for 4 samples)
}
}
}
+GAMDisplayThread1 = {
Class = IOGAM
InputSignals = {
Counter = {
DataSource = DDB1
Type = uint32
}
GainCounter1Thread1 = {
DataSource = DDB1
Type = uint32
}
GainCounter2Thread1 = {
DataSource = DDB1
Type = uint32
}
GainCounter3Thread1 = {
DataSource = DDB1
Type = uint32
}
}
OutputSignals = {
Counter = {
DataSource = LoggerDataSource
Type = uint32
}
GainCounter1Thread1 = {
DataSource = LoggerDataSource
Type = uint32
}
GainCounter2Thread1 = {
DataSource = LoggerDataSource
Type = uint32
}
GainCounter3Thread1 = {
DataSource = LoggerDataSource
Type = uint32
}
}
}
+GAMDisplayThread2 = {
Class = IOGAM
InputSignals = {
GainCounter1Thread2 = {
DataSource = DDB1
Type = uint32
}
GainCounter2Thread2 = {
DataSource = DDB1
Type = uint32
}
GainCounter3Thread2 = {
DataSource = DDB1
Type = uint32
}
}
OutputSignals = {
GainCounter1Thread2 = {
DataSource = LoggerDataSource
Type = uint32
NumberOfDimensions = 1
NumberOfElements = 2
}
GainCounter2Thread2 = {
DataSource = LoggerDataSource
Type = uint32
NumberOfDimensions = 1
NumberOfElements = 2
}
GainCounter3Thread2 = {
DataSource = LoggerDataSource
Type = uint32
NumberOfDimensions = 1
NumberOfElements = 2
}
}
}
+GAMDisplayThread3 = {
Class = IOGAM
InputSignals = {
GainCounter1Thread3 = {
DataSource = DDB1
Type = uint32
}
GainCounter2Thread3 = {
DataSource = DDB1
Type = uint32
}
GainCounter3Thread3 = {
DataSource = DDB1
Type = uint32
}
}
OutputSignals = {
GainCounter1Thread3 = {
DataSource = LoggerDataSource
Type = uint32
NumberOfDimensions = 1
NumberOfElements = 4
}
GainCounter2Thread3 = {
DataSource = LoggerDataSource
Type = uint32
NumberOfDimensions = 1
NumberOfElements = 4
}
GainCounter3Thread3 = {
DataSource = LoggerDataSource
Type = uint32
NumberOfDimensions = 1
NumberOfElements = 4
}
}
}
}
+Data = {
Class = ReferenceContainer
DefaultDataSource = DDB1
+DDB1 = {
Class = GAMDataSource
}
+LoggerDataSource = {
Class = LoggerDataSource
}
+Timings = {
Class = TimingDataSource
}
+RTThreadSynch = {
Class = RealTimeThreadSynchronisation
Timeout = 10000 //Timeout in ms to wait for the thread to cycle.
}
+Timer = {
Class = LinuxTimer
SleepNature = "Default"
Signals = {
Counter = {
Type = uint32
}
Time = {
Type = uint32
}
}
}
}
+States = {
Class = ReferenceContainer
+State1 = {
Class = RealTimeState
+Threads = {
Class = ReferenceContainer
+Thread1 = {
Class = RealTimeThread
CPUs = 0x1
Functions = {GAMTimer GAMVariable1 GAMT1TSynchOut GAMDisplayThread1 }
}
+Thread2 = {
Class = RealTimeThread
CPUs = 0x2
Functions = {GAMT1T2Interface GAMDisplayThread2 }
}
+Thread3 = {
Class = RealTimeThread
CPUs = 0x4
Functions = {GAMT1T3Interface GAMDisplayThread3 }
}
}
}
}
+Scheduler = {
Class = GAMScheduler
TimingDataSource = Timings
}
}
|
Instructions on how to compile and execute the examples can be found here.