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.

Makefile configuration to set the UDP port number.
 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.

UDPSender configuration. Note that the port number is set from the variable 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.

  1. Edit the file ../Configurations/MassSpring/RTApp-MassSpring-24.cfg and modify the DataSource UDPWriterReference to stream the signals: Counter, Time and ReferencePosition to the UDP port identified as TUTORIAL_UDP_PORT_1.

  2. Add an IOGAM to copy the signals from the DDB1 into the UDPWriterReference. Add the GAM to the execution list.

  3. Run make -C ../Configurations/MassSpring/ -f Makefile.cfg to generate the configuration file with the correct UDP port numbers.

  4. Check that the application statistics are still being streamed over UDP to the port identified as TUTORIAL_UDP_PORT_2 and that the ReferencePosition is being streamed to the port identified as TUTORIAL_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.

Updated UDPWriterReference configuration.
 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        }
IOGAM to copy data from 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        }
Updated GAM execution list.
 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    }