UDPSender
The UDPSender DataSource can be used to stream application data over UDP.
Typically, use cases include streaming data to a remote monitoring or control application.
In this section, the FileWriter named FileWriterStats will be replaced by a UDPSender.
This DataSource can also be used to stream data asynchronously to the RealTimeThread, as discussed for the FileWriter, but typically UDP streaming is used for real-time data and is thus set with ExecutionMode = RealTimeThread.
Given that the UDP port number is highly dependent on the system configuration, the configuration file ../Configurations/MassSpring/RTApp-MassSpring-23-Sender.cfg will be automatically updated from a Makefile.cfg, as explained in the section Preprocessing of the documentation.
1#Named of the unit files to be compiled
2OBJSX=RTApp-MassSpring-23-Sender.x \
3 RTApp-MassSpring-24-Sender.x \
4 RTApp-MassSpring-24-Sender-solution.x \
5 RTApp-MassSpring-24-Receiver.x \
6 RTApp-MassSpring-25-Receiver.x \
7 RTApp-MassSpring-25-Receiver-solution.x \
8 RTApp-MassSpring-26-Publisher.x \
9 RTApp-MassSpring-27-Publisher.x \
10 RTApp-MassSpring-27-Publisher-solution.x \
11 RTApp-MassSpring-28-Publisher.x \
12 RTApp-MassSpring-28-Subscriber.x \
13 RTApp-MassSpring-29-Subscriber.x \
14 RTApp-MassSpring-29-Subscriber-solution.x \
15 RTApp-MassSpring-30.x \
16 RTApp-MassSpring-31.x \
17 RTApp-MassSpring-31-solution.x \
18 RTApp-MassSpring-32.x \
19 RTApp-MassSpring-33.x \
20 RTApp-MassSpring-33-solution.x \
21 RTApp-MassSpring-36.x \
22 RTApp-MassSpring-37.x \
23 RTApp-MassSpring-37-solution.x \
24 RTApp-MassSpring-38.x \
25 RTApp-MassSpring-39.x \
26 RTApp-MassSpring-39-solution.x \
The Makefile will automatically call the script ../Test/Integrated/FindFreeUDPPort.sh to find a free UDP port number, which will then be used by the Makefile to update the variable TUTORIAL_UDP_PORT in the generated configuration file ../Configurations/MassSpring/RTApp-MassSpring-23-Sender_Gen.cfg.
TUTORIAL_UDP_PORT, which is replaced by the Makefile.cfg. 1 +UDPWriterStats = {
2 Class = UDP::UDPSender
3 Address = "127.0.0.1"
4 Port = TUTORIAL_UDP_PORT
5 ExecutionMode = RealTimeThread
6 Signals = {
7 Thread1CycleTime = {
8 Type = uint32
9 }
10 Thread1CycleTimeAverage = {
11 Type = uint32
12 }
13 Thread1CycleTimeStdDev = {
14 Type = uint32
15 }
16 Thread1CycleTimeMax = {
17 Type = uint32
18 }
19 Thread1CycleTimeMin = {
20 Type = uint32
21 }
22 Thread1CycleTimeHistogram = {
23 Type = uint32
24 NumberOfElements = 11
25 }
26 Thread1FreeTimeHistogram = {
27 Type = uint32
28 NumberOfElements = 11
29 }
30 GAMsExecutionTime = {
31 Type = uint32
32 }
33 }
34 }
Warning
Some DataSources allow for implicit signal declaration, meaning that the signals are not explicitly declared as part of the DataSource configuration, but are automatically created based on the signals being written to or read from the DataSource.
This is not the case for the UDPSender DataSource, which requires that all signals are explicitly declared as part of its configuration.
An attempt to write a signal to a UDPSender DataSource that has not been declared as part of the DataSource configuration will result in an error similar to the following:
$ [InitialisationEr - RealTimeApplicationConfigurationBuilder.cpp:1183]: Cannot add the signal Time in GAM GAMWriterRefPos because the related DataSource is locked
Running the application
Generate the configuration file:
make -C ../Configurations/MassSpring/ -f Makefile.cfg
Note the UDP port number being used in the generated configuration file ../Configurations/MassSpring/RTApp-MassSpring-23-Sender_Gen.cfg or by checking the output of the Makefile command, which should show a line similar to the following (look for the line with -DTUTORIAL_UDP_PORT):
gcc -x c -P -E -DTUTORIAL_UDP_PORT=42700 RTApp-MassSpring-23-Sender.cfg -o ./RTApp-MassSpring-23-Sender_Gen.cfg
RTApp-MassSpring-23-Sender.cfg:364:26: warning: missing terminating " character
Expression = "m=1.0;
RTApp-MassSpring-23-Sender.cfg:370:51: warning: missing terminating " character
PositionM_1 = PositionM;"
RTApp-MassSpring-23-Sender.cfg:564:26: warning: missing terminating " character
Expression = "
RTApp-MassSpring-23-Sender.cfg:566:77: warning: missing terminating " character
TriggerWriter = (uint8)(Time < (uint32)MaxAppTimeMicroSecs);"
RTApp-MassSpring-23-Sender.cfg:582:26: warning: missing terminating " character
Expression = "
RTApp-MassSpring-23-Sender.cfg:585:65: warning: missing terminating " character
TriggerDisplay = (uint8)(Time == TruncatedTime);"
Start the application with:
./MARTeApp.sh -f ../Configurations/MassSpring/RTApp-MassSpring-23-Sender_Gen.cfg -l RealTimeLoader -s State1
Once the application is running, inspect the screen output and verify that the application is running without any issues. The log should show entries similar to the following:
$ [Warning - Threads.cpp:181]: Failed to change the thread priority (likely due to insufficient permissions)
$ [Information - RealTimeLoader.cpp:111]: Started application in state State1
$ [Information - MARTeApp.cpp:135]: Application starting
$ [Information - LoggerBroker.cpp:152]: Time [0:0]:1000000
...
A Python script to receive the UDP data and print it to the console is available in the file ../Test/Integrated/UDPReceiver.py.
Open another terminal and run the script with:
TUTORIAL_UDP_PORT=`awk '/\+UDPWriterStats/,/}/ {if ($1=="Port") print $3}' ../Configurations/MassSpring/RTApp-MassSpring-23-Sender_Gen.cfg`;echo "TUTORIAL_UDP_PORT=$TUTORIAL_UDP_PORT"
python ../Test/Integrated/udp_monitor.py -p $TUTORIAL_UDP_PORT
Exercises
Ex. 1: Stream the ReferencePosition signal over UDP.
Edit the file
../Configurations/MassSpring/RTApp-MassSpring-24.cfgand modify the DataSourceUDPWriterReferenceto stream the signals:Counter,TimeandReferencePositionto the UDP port identified asTUTORIAL_UDP_PORT_1.Add an
IOGAMto copy the signals from theDDB1into theUDPWriterReference. Add the GAM to the execution list.Run
make -C ../Configurations/MassSpring/ -f Makefile.cfgto generate the configuration file with the correct UDP port numbers.Check that the application statistics are still being streamed over UDP to the port identified as
TUTORIAL_UDP_PORT_2and that theReferencePositionis being streamed to the port identified asTUTORIAL_UDP_PORT_1.
make -C ../Configurations/MassSpring/ -f Makefile.cfg
./MARTeApp.sh -f ../Configurations/MassSpring/RTApp-MassSpring-24-Sender_Gen.cfg -l RealTimeLoader -s State1
TUTORIAL_UDP_PORT_2=`awk '/\+UDPWriterStats/,/}/ {if ($1=="Port") print $3}' ../Configurations/MassSpring/RTApp-MassSpring-24-Sender_Gen.cfg`;echo "TUTORIAL_UDP_PORT_2=$TUTORIAL_UDP_PORT_2"
python ../Test/Integrated/udp_monitor.py -p $TUTORIAL_UDP_PORT_2
TUTORIAL_UDP_PORT_1=`awk '/\+UDPWriterReference/,/}/ {if ($1=="Port") print $3}' ../Configurations/MassSpring/RTApp-MassSpring-24-Sender_Gen.cfg`;echo "TUTORIAL_UDP_PORT_1=$TUTORIAL_UDP_PORT_1"
python ../Test/Integrated/udp_monitor.py -p $TUTORIAL_UDP_PORT_1 -s 2 #Note that the signal index is set to 2, which corresponds to expecting a packet with the ``ReferencePosition`` signal in the payload.
Solution
The solution is to modify the configuration file ../Configurations/MassSpring/RTApp-MassSpring-24-Sender.cfg and complete the necessary changes to the UDPWriterReference DataSource and to add the necessary GAM to copy the ReferencePosition signal into the UDPWriterReference DataSource.
1 +UDPWriterReference = {
2 Class = UDP::UDPSender
3 Address = "127.0.0.1"
4 Port = TUTORIAL_UDP_PORT_1
5 ExecutionMode = RealTimeThread
6 Signals = {
7 Counter = {
8 Type = uint32
9 }
10 Time = {
11 Type = uint32
12 }
13 ReferencePosition = {
14 Type = float64
15 }
16 }
17 }
DDB1 to UDPWriterReference. 1 +GAMWriterRefPos = {
2 Class = IOGAM
3 InputSignals = {
4 Counter = {
5 DataSource = DDB1
6 Type = uint32
7 }
8 Time = {
9 DataSource = DDB1
10 Type = uint32
11 }
12 ReferencePosition = {
13 DataSource = DDB1
14 Type = float64
15 }
16 }
17 OutputSignals = {
18 Counter = {
19 DataSource = UDPWriterReference
20 Type = uint32
21 }
22 Time = {
23 DataSource = UDPWriterReference
24 Type = uint32
25 }
26 ReferencePosition = {
27 DataSource = UDPWriterReference
28 Type = float64
29 }
30 }
31 }
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 = {GAMPerfMonitor GAMTimer GAMReferenceWaveform GAMHist GAMStats GAMMathExpr GAMMathTriggerSecond GAMWriterRefPos GAMWriterStats GAMDisplay}
11 }
12 }
13 }
14 }