Hello World

Important

Two implicit rules:

  • All commands are assumed to be run from the $MARTE_TRAINING_PARENT_DIR/MARTe2-training-proj/Startup directory, unless otherwise specified.

  • When more than one application must be executed in parallel, a new terminal needs to be opened for each application.

Run the application

Start the application with:

cd $MARTE_TRAINING_PARENT_DIR/MARTe2-training-proj/Startup
 ./MARTeApp.sh -f ../Configurations/HelloWorld/RTApp-HelloWorld-1.cfg -l RealTimeLoader -s State1

Once the application is running, inspect the screen output and verify that the log shows the counter increasing:

$ [Information - LoggerBroker.cpp:152]: Counter [0:0]:1
$ [Information - LoggerBroker.cpp:152]: Counter [0:0]:2
...

If these messages appear, the Hello World MARTe2 application has started successfully.

To stop the application, press Ctrl+C in the terminal where it is running.

Notes on common warning messages

Warning

While running the application, you may observe messages such as:

$ [Warning - Threads.cpp:169]: Requested a thread priority that is higher ...
$ [Warning - Threads.cpp:181]: Failed to change the thread priority ...

These warnings are caused by insufficient user permissions to set real-time thread priorities.

For development purposes, they can be safely ignored and do not affect the functional behaviour of the application.

In a production environment, however, running without the appropriate permissions may impact real-time performance.

Understanding what just ran

The HelloWorld application that was launched in the previous step is fully described by the file:

../Configurations/HelloWorld/RTApp-HelloWorld-1.cfg

Rather than hard-coding the application structure in C++, MARTe2 uses a configuration-based approach. This means that the execution states, scheduling behaviour, functional blocks, and signal connections are all described in the configuration.

When the command below was executed:

./MARTeApp.sh -f ../Configurations/HelloWorld/RTApp-HelloWorld-1.cfg -l RealTimeLoader -s State1

MARTe2 loaded this configuration, created the RealTimeApplication, selected the State1 state, and started executing it.

RealTimeApplication

At the top level (but not necessarily at the beginning of the file) of every MARTe2 configuration there is a RealTimeApplication. This component defines the overall structure and behaviour of the application.

Note

A MARTe configuration file may contain multiple RealTimeApplication instances.

The RealTimeApplication is always composed of the following sections:

  • +Functions: defines the processing components (GAMs)

  • +Data: defines the data sources

  • +States: defines the execution states (e.g. State1) and their RealTimeThread instances

  • +Scheduler: controls how the application is executed

MARTe RealTimeApplication.
 1$HelloWorldApp = {
 2    Class = RealTimeApplication
 3    +Functions = {
 4        Class = ReferenceContainer
 5    +Data = {
 6        Class = ReferenceContainer
 7    +States = {
 8        Class = ReferenceContainer
 9    +Scheduler = {
10        Class = GAMScheduler

Functions

Two functional blocks (GAMs) are executed in the thread: GAMTimer and GAMDisplay.

The first is an IOGAM responsible for getting a counter and a timer signal from a DataSource named Timer and copying these signals to a GAMDataSource.

IOGAM named GAMTimer
 1        +GAMTimer = {
 2            Class = IOGAM
 3            InputSignals = {
 4                Counter = {
 5                    DataSource = Timer
 6                    Type = uint32
 7                }
 8                Time = {
 9                    Frequency = 1
10                    DataSource = Timer
11                    Type = uint32
12                }
13            }
14            OutputSignals = {
15                Counter = {
16                    DataSource = DDB1
17                    Type = uint32
18                }                
19                Time = {
20                    DataSource = DDB1
21                    Type = uint32
22                }            
23            }
24        }

The Frequency is a special signal property that defines the rate at which the thread executes. The actual pacing of the thread is determined by the DataSource that provides the signal with the Frequency property. In this case, the Timer DataSource is configured to execute at a frequency of 1 Hz.

The second is an IOGAM that takes care of copying the signals from the GAMDataSource and offering them to a DataSource named Display.

GAMDisplay IOGAM
 1        +GAMDisplay = {
 2            Class = IOGAM            
 3            InputSignals = {
 4                Counter = {
 5                    DataSource = DDB1
 6                    Type = uint32
 7                }
 8            } 
 9            OutputSignals = {
10                Counter = {
11                    DataSource = Display 
12                    Type = uint32
13                }
14            }
15        }

DataSources

The MARTe +Data provide an interface between the functional blocks (GAMs) and the outside world. They are responsible for acquiring data from external sources (e.g. hardware, files, network) and making it available to the GAMs, as well as for taking data from the GAMs and sending it to external sinks. Two DataSources are defined in the configuration: Timer (of type LinuxTimer) and Display (of type LoggerDataSource).

LinuxTimer DataSource
 1        +Timer = {
 2            Class = LinuxTimer
 3            SleepNature = "Default"
 4            Signals = {
 5                Counter = {
 6                    Type = uint32
 7                }
 8                Time = {
 9                    Type = uint32
10                }
11            }
12        }        
LoggerDataSource
1        +Display = {
2            Class = LoggerDataSource
3        }

States and Threads

In the HelloWorld example, a single state (State1), with a single thread (Thread), is defined. The thread executes the two GAMs described in the previous section.

MARTe RealTimeState definition.
 1    +States = {
 2        Class = ReferenceContainer
 3        +State1 = {
 4            Class = RealTimeState
 5            +Threads = {
 6                Class = ReferenceContainer
 7                +Thread1 = {
 8                    Class = RealTimeThread
 9                    CPUs = 0x1
10                    Functions = {GAMTimer GAMDisplay}
11                }
12            }
13        }        
14    }

Scheduler

MARTe allows the default GAMScheduler component to be modified, but this is meant only for special applications (e.g. in embedded systems). For most applications, the default scheduler is sufficient.