/**
 * Test MARTe2 application for UDPStreamer DataSource.
 *
 * Three independent RT threads demonstrate all four UDPStreamer time modes:
 *
 * Thread1 – "Streamer" port 44500 TCP control / 44503 UDP multicast 239.0.0.1
 *           (scalar signals, auto-accumulated to arrays[10], multicast mode,
 *            100 Hz flush = 10 samples per packet, 1 kHz source)
 *   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) ─────────────────
        //  Multicast mode: clients connect via TCP on port 44500 to receive the
        //  CONFIG packet, then join 239.0.0.1:44503 to receive DATA datagrams.
        //  Auto publishing ensures data is sent every RT cycle (1 kHz = 1 ms
        //  temporal resolution) but never faster, so the rate is bounded.
        +Streamer = {
            Class = UDPStreamer
            Port = 44500
            MulticastGroup = "239.0.0.1"
            DataPort = 44503
            MaxPayloadSize = 1400
            PublishingMode = "Accumulate"
            MinRefreshRate = 100
            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
    }
}
