/** * Test MARTe2 application for UDPStreamer DataSource. * * Three independent RT threads demonstrate all four UDPStreamer time modes: * * Thread1 – "Streamer" port 44500 (scalar signals, PacketTime) * Counter – uint32 cycle counter * Time – uint32 time in microseconds (LinuxTimer, 1 kHz) * Sine1 – float32, 1 Hz, quantised to uint16 on wire (PacketTime) * Sine2 – float32, 0.3 Hz, raw float32 on wire (PacketTime) * * Thread2 – "FastStreamer" port 44501 (packed arrays, FirstSample + LastSample) * Time – uint32 scalar anchor (5 kHz LinuxTimer) * Ch1 – float32[1000], 1 kHz sine (TimeMode = FirstSample) * Ch2 – float32[1000], 10 kHz sine (TimeMode = LastSample) * Both channels use Time as the anchor and SamplingRate = 5 000 000 Hz so * the WebUI reconstructs the 200 ns per-sample timestamps. * * Thread3 – "FullArrStreamer" port 44502 (packed arrays, FullArray) * TimeArray – uint64[1000] per-sample timestamps in ns generated by TimeArrayGAM * Ch3 – float32[1000], 3 kHz sine (TimeMode = FullArray) * Ch4 – float32[1000], 500 Hz sine (TimeMode = FullArray) * The WebUI uses the explicit timestamp for each sample rather than * reconstructing them from a scalar anchor. */ $TestApp = { Class = RealTimeApplication +Functions = { Class = ReferenceContainer // ── Copy Counter + Time from LinuxTimer into the inter-GAM DDB ────── +TimerGAM = { Class = IOGAM InputSignals = { Counter = { DataSource = Timer Type = uint32 } Time = { Frequency = 1000 DataSource = Timer Type = uint32 } } OutputSignals = { Counter = { DataSource = DDB Type = uint32 } Time = { DataSource = DDB Type = uint32 } } } // ── 5 kHz fast timer for packed-array threads ──────────────────────── +FastTimerGAM = { Class = IOGAM InputSignals = { Time = { Frequency = 5000 DataSource = FastTimer Type = uint32 } } OutputSignals = { Time = { DataSource = DDB2 Type = uint32 } } } // ── 1 Hz sinusoidal signal ─────────────────────────────────────────── +SineGAM1 = { Class = WaveformSin Amplitude = 10.0 Frequency = 1.0 Phase = 0.0 Offset = 0.0 InputSignals = { Time = { DataSource = DDB Type = uint32 } } OutputSignals = { Sine1 = { DataSource = DDB Type = float32 } } } // ── 0.3 Hz sinusoidal signal (phase-shifted) ───────────────────────── +SineGAM2 = { Class = WaveformSin Amplitude = 5.0 Frequency = 0.3 Phase = 1.0472 Offset = 0.0 InputSignals = { Time = { DataSource = DDB Type = uint32 } } OutputSignals = { Sine2 = { DataSource = DDB Type = float32 } } } // ── 1 kHz sine burst – channel 1 (FirstSample anchor) ─────────────── +SineGAM3 = { Class = SineArrayGAM Frequency = 1000.0 Amplitude = 1.0 Phase = 0.0 Offset = 0.0 SamplingRate = 5000000.0 OutputSignals = { Ch1 = { DataSource = DDB2 Type = float32 NumberOfDimensions = 1 NumberOfElements = 1000 } } } // ── 10 kHz sine burst – channel 2 (LastSample anchor) ─────────────── +SineGAM4 = { Class = SineArrayGAM Frequency = 10000.0 Amplitude = 0.5 Phase = 1.5708 Offset = 0.0 SamplingRate = 5000000.0 OutputSignals = { Ch2 = { DataSource = DDB2 Type = float32 NumberOfDimensions = 1 NumberOfElements = 1000 } } } // ── Route scalar signals → Streamer ────────────────────────────────── +StreamerGAM = { Class = IOGAM InputSignals = { Counter = { DataSource = DDB Type = uint32 } Time = { DataSource = DDB Type = uint32 } Sine1 = { DataSource = DDB Type = float32 } Sine2 = { DataSource = DDB Type = float32 } } OutputSignals = { Counter = { DataSource = Streamer Type = uint32 } Time = { DataSource = Streamer Type = uint32 } Sine1 = { DataSource = Streamer Type = float32 } Sine2 = { DataSource = Streamer Type = float32 } } } // ── Route packed arrays → FastStreamer (FirstSample + LastSample) ──── +FastStreamerGAM = { Class = IOGAM InputSignals = { Time = { DataSource = DDB2 Type = uint32 } Ch1 = { DataSource = DDB2 Type = float32 NumberOfDimensions = 1 NumberOfElements = 1000 } Ch2 = { DataSource = DDB2 Type = float32 NumberOfDimensions = 1 NumberOfElements = 1000 } } OutputSignals = { Time = { DataSource = FastStreamer Type = uint32 } Ch1 = { DataSource = FastStreamer Type = float32 NumberOfDimensions = 1 NumberOfElements = 1000 } Ch2 = { DataSource = FastStreamer Type = float32 NumberOfDimensions = 1 NumberOfElements = 1000 } } } // ── 3 kHz sine burst – channel 3 (FullArray anchor) ───────────────── +SineGAM5 = { Class = SineArrayGAM Frequency = 3000.0 Amplitude = 2.0 Phase = 0.0 Offset = 0.0 SamplingRate = 5000000.0 OutputSignals = { Ch3 = { DataSource = DDB3 Type = float32 NumberOfDimensions = 1 NumberOfElements = 1000 } } } // ── 500 Hz sine burst – channel 4 (FullArray anchor) ───────────────── +SineGAM6 = { Class = SineArrayGAM Frequency = 500.0 Amplitude = 3.0 Phase = 0.7854 Offset = 0.0 SamplingRate = 5000000.0 OutputSignals = { Ch4 = { DataSource = DDB3 Type = float32 NumberOfDimensions = 1 NumberOfElements = 1000 } } } // ── Build per-sample time array for FullArray channels ──────────────── // TimeArrayGAM expands the scalar LinuxTimer Time (uint32, µs) into a // uint64[1000] array in nanoseconds where element[k] = Time_ns + k * period_ns. // Using ns preserves sub-µs resolution at sampling rates > 1 MHz. +TimeArrayGAM1 = { Class = TimeArrayGAM SamplingRate = 5000000.0 Anchor = FirstSample InputSignals = { Time = { DataSource = DDB3 Type = uint32 } } OutputSignals = { TimeArray = { DataSource = DDB3 Type = uint64 NumberOfDimensions = 1 NumberOfElements = 1000 } } } // ── Fast timer for FullArray thread ─────────────────────────────────── +FullArrTimerGAM = { Class = IOGAM InputSignals = { Time = { Frequency = 5000 DataSource = FullArrTimer Type = uint32 } } OutputSignals = { Time = { DataSource = DDB3 Type = uint32 } } } // ── Route FullArray channels → FullArrStreamer ───────────────────── +FullArrStreamerGAM = { Class = IOGAM InputSignals = { TimeArray = { DataSource = DDB3 Type = uint64 NumberOfDimensions = 1 NumberOfElements = 1000 } Ch3 = { DataSource = DDB3 Type = float32 NumberOfDimensions = 1 NumberOfElements = 1000 } Ch4 = { DataSource = DDB3 Type = float32 NumberOfDimensions = 1 NumberOfElements = 1000 } } OutputSignals = { TimeArray = { DataSource = FullArrStreamer Type = uint64 NumberOfDimensions = 1 NumberOfElements = 1000 } Ch3 = { DataSource = FullArrStreamer Type = float32 NumberOfDimensions = 1 NumberOfElements = 1000 } Ch4 = { DataSource = FullArrStreamer Type = float32 NumberOfDimensions = 1 NumberOfElements = 1000 } } } } +Data = { Class = ReferenceContainer DefaultDataSource = DDB +DDB = { Class = GAMDataSource } +DDB2 = { Class = GAMDataSource } +DDB3 = { Class = GAMDataSource } // ── 1 kHz real-time clock (Thread1) ────────────────────────────────── +Timer = { Class = LinuxTimer SleepNature = "Default" Signals = { Counter = { Type = uint32 } Time = { Type = uint32 } } } // ── 5 kHz fast timer (Thread2 – FirstSample / LastSample) ──────────── +FastTimer = { Class = LinuxTimer SleepNature = "Default" Signals = { Counter = { Type = uint32 } Time = { Type = uint32 } } } // ── 5 kHz fast timer (Thread3 – FullArray) ─────────────────────────── +FullArrTimer = { Class = LinuxTimer SleepNature = "Default" Signals = { Counter = { Type = uint32 } Time = { Type = uint32 } } } // ── Streamer: scalar signals, PacketTime (port 44500) ───────────────── +Streamer = { Class = UDPStreamer Port = 44500 MaxPayloadSize = 1400 Signals = { Counter = { Type = uint32 } Time = { Type = uint32 Unit = "us" } Sine1 = { Type = float32 Unit = "V" RangeMin = -10.0 RangeMax = 10.0 QuantizedType = "uint16" } Sine2 = { Type = float32 Unit = "V" RangeMin = -5.0 RangeMax = 5.0 } } } // ── FastStreamer: packed arrays, FirstSample + LastSample (port 44501) // // Ch1 uses TimeMode = FirstSample: // Time is the timestamp of sample [0]; later samples are extrapolated // forward: t[k] = Time + k / SamplingRate. // // Ch2 uses TimeMode = LastSample: // Time is the timestamp of sample [N-1]; earlier samples are // extrapolated backward: t[k] = Time - (N-1-k) / SamplingRate. // // Both modes produce identical wall-clock placements for a fixed-rate // signal and are shown here side-by-side for comparison. +FastStreamer = { Class = UDPStreamer Port = 44501 MaxPayloadSize = 1400 Signals = { Time = { Type = uint32 Unit = "us" } Ch1 = { Type = float32 Unit = "V" NumberOfDimensions = 1 NumberOfElements = 1000 TimeMode = FirstSample TimeSignal = Time SamplingRate = 5000000.0 } Ch2 = { Type = float32 Unit = "V" NumberOfDimensions = 1 NumberOfElements = 1000 TimeMode = LastSample TimeSignal = Time SamplingRate = 5000000.0 } } } // ── FullArrStreamer: packed arrays, FullArray (port 44502) ───────────── // // TimeMode = FullArray: the TimeSignal (TimeArray) has the same // NumberOfElements as the data channel. Each sample pair // (TimeArray[k], Ch3[k]) provides its own independent timestamp. // This mode handles non-uniform sampling and explicit per-sample clocks. +FullArrStreamer = { Class = UDPStreamer Port = 44502 MaxPayloadSize = 1400 Signals = { TimeArray = { Type = uint64 Unit = "ns" NumberOfDimensions = 1 NumberOfElements = 1000 } Ch3 = { Type = float32 Unit = "V" NumberOfDimensions = 1 NumberOfElements = 1000 TimeMode = FullArray TimeSignal = TimeArray } Ch4 = { Type = float32 Unit = "V" NumberOfDimensions = 1 NumberOfElements = 1000 TimeMode = FullArray TimeSignal = TimeArray } } } +Timings = { Class = TimingDataSource } } +States = { Class = ReferenceContainer +Running = { Class = RealTimeState +Threads = { Class = ReferenceContainer // Thread1: scalar signals at 1 kHz +Thread1 = { Class = RealTimeThread CPUs = 0x1 Functions = {TimerGAM SineGAM1 SineGAM2 StreamerGAM} } // Thread2: packed arrays at 5 kHz (FirstSample + LastSample) +Thread2 = { Class = RealTimeThread CPUs = 0x2 Functions = {FastTimerGAM SineGAM3 SineGAM4 FastStreamerGAM} } // Thread3: packed arrays at 5 kHz (FullArray with explicit timestamps) +Thread3 = { Class = RealTimeThread CPUs = 0x4 Functions = {FullArrTimerGAM SineGAM5 SineGAM6 TimeArrayGAM1 FullArrStreamerGAM} } } } } +Scheduler = { Class = GAMScheduler TimingDataSource = Timings } }