#!/usr/bin/env python3 # SPDX-License-Identifier: MIT # SPDX-FileCopyrightText: 2026 Martino Ferrari """A minimal UDPStreamer (UDPS) producer, for exercising udpscope without MARTe2. Unicast only: binds `--port`, waits for a CONNECT datagram, then streams CONFIG once and DATA packets to whoever connected. Publish mode is Accumulate, so each packet carries `--batch` consecutive samples per (scalar) signal -- the shape the viewer's per-sample path expects. Signals: `time` (the stream's own clock, seconds), `sine`, `square`, `ramp`. Everything is float64 and unquantised. ./tools/mock_udpstreamer.py --port 8000 --rate 10000 --batch 100 """ import argparse import math import random import socket import struct import time MAGIC = 0x53504455 PKT_DATA, PKT_CONFIG, PKT_ACK, PKT_CONNECT, PKT_DISCONNECT = 0, 1, 2, 3, 4 T_FLOAT64 = 9 QUANT_NONE = 0 TIME_PACKET, TIME_FULL_ARRAY = 0, 1 PUBLISH_ACCUMULATE = 1 NO_TIME_SIGNAL = 0xFFFFFFFF def header(pkt_type, counter, payload_bytes): return struct.pack("= 0.0 else -1.0 for t in stamps] ramp = [(freq * t) % 1.0 * 2.0 - 1.0 for t in stamps] payload = struct.pack("= 17: magic, ptype = struct.unpack_from(" 0.0: pdt = dt * (1.0 + random.uniform(-args.clock_jitter, args.clock_jitter)) sock.sendto(build_data(counter, t_stream, pdt, args.batch, args.freq), peer) counter += 1 t_stream += args.batch * pdt next_send += period if args.duration > 0.0 and started is not None and now - started > args.duration: print("mock udpstreamer: done (%d packets)" % counter, flush=True) return if __name__ == "__main__": main()