#!/usr/bin/env python3
"""
Generate a multi-signal binary test file for MARTe2 FileReader.

Format (per signal descriptor):
- 2B TypeDescriptor.all (uint16 LE)
- 32B signal name (null-padded)
- 4B numElements (uint32 LE)
Header: [4B numSigs] [signal desc...] [raw float32 data rows]

Three signals with different sizes to verify no data scrambling:
  Signal_100: 100   float32 values per row
  Signal_1K:  1000  float32 values per row
  Signal_5K:  5000  float32 values per row
"""
import struct
import os

OUTPUT = "/tmp/udpstreamer_test_input.bin"
NUM_ROWS = 100
TYPE_FLOAT32 = 2056  # MARTe2 TypeDescriptor.all for Float32Bit

SIGNALS = [
    ("Signal_100", 100,   lambda r, c: float(r * 1000 + c) / 100.0),
    ("Signal_1K",  1000,  lambda r, c: float(r * 500  + c) / 50.0),
    ("Signal_5K",  5000,  lambda r, c: float(r * 200  + c) / 20.0),
]

def generate():
    with open(OUTPUT, "wb") as f:
        # Header: numSigs
        f.write(struct.pack("<I", len(SIGNALS)))

        # Signal descriptors
        for name, nelems, _ in SIGNALS:
            f.write(struct.pack("<H", TYPE_FLOAT32))
            padded = (name + "\0").encode() + b"\0" * 32
            f.write(padded[:32])
            f.write(struct.pack("<I", nelems))

        # Data rows
        total_floats = sum(n for _, n, _ in SIGNALS)
        for row in range(NUM_ROWS):
            values = []
            for _, nelems, func in SIGNALS:
                for col in range(nelems):
                    values.append(func(row, col))
            f.write(struct.pack(f"<{total_floats}f", *values))

    size = os.path.getsize(OUTPUT)
    header_size = 4 + len(SIGNALS) * (2 + 32 + 4)
    data_size = NUM_ROWS * total_floats * 4
    print(f"Generated {OUTPUT}: {size} bytes")
    print(f"  Header: {header_size} B, Data: {data_size} B")
    print(f"  {NUM_ROWS} rows x {total_floats} floats ({', '.join(f'{n}' for _, n, _ in SIGNALS)} per signal)")
    print(f"  Total: {size} bytes")

    # Verify
    with open(OUTPUT, "rb") as f:
        ns = struct.unpack("<I", f.read(4))[0]
        print(f"  Verified: {ns} signals")
        for i in range(ns):
            tc = struct.unpack("<H", f.read(2))[0]
            nm = f.read(32).rstrip(b"\0").decode()
            ne = struct.unpack("<I", f.read(4))[0]
            print(f"    {nm}: type={tc}, elems={ne}")

        # Verify first row first few values of each signal
        data = f.read()
        offsets = [0]
        for _, ne, _ in SIGNALS:
            offsets.append(offsets[-1] + ne * 4)
        for i, (name, ne, _) in enumerate(SIGNALS):
            off = offsets[i]
            vals = struct.unpack(f"<{min(5, ne)}f", data[off:off + min(5, ne) * 4])
            print(f"    {name} row 0 (first 5): {[round(v, 4) for v in vals]}")

if __name__ == "__main__":
    generate()
