DataSource (C++):
- New optional config: MulticastGroup (e.g. "239.0.0.1") and DataPort
(default Port+1); when set, enables multicast mode; absent = unicast
- Control plane: BasicTCPSocket listener on Port; CONNECT received over
TCP triggers HandleTCPConnect() which sends CONFIG via the same TCP
connection
- Data plane: BasicUDPSocket aimed at MulticastGroup:DataPort; all DATA
fragments sent via dataSocket.Write() so any joined client receives them
- useMulticast is the single branch point; every unicast code path is
unchanged when MulticastGroup is absent
- New methods: HandleTCPConnect(), IsMulticast()
- 5 new unit tests (ports 44710-44729); all 38 tests passing
WebUI hub (Go):
- SourceConfig gains MulticastGroup and DataPort fields (JSON, optional)
- UDPClient gains multicastGroup/dataPort; Run() routes to new
runMulticastSession() when multicastGroup is non-empty
- runMulticastSession(): TCP dial for CONNECT/CONFIG, net.ListenMulticastUDP
for DATA, background goroutine watches TCP for DISCONNECT/close
- All existing sm.Add() call sites updated (unicast callers pass "", 0)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
UDPStreamer:
- Add PublishingMode = "Strict" | "Auto" config parameter
- Add MinRefreshRate (Hz) for Auto mode; uses HRT phase-locked tick
counting to rate-limit sends without accumulation buffers
- Fix high-frequency integration test configs to use newline-separated
key-value pairs (MARTe2 StandardParser does not treat ';' as delimiter)
- Add 3 new unit tests (AutoMode_Valid, AutoMode_MissingRefreshRate,
UnknownPublishingMode); all 33 tests passing
WebUI hub:
- Skip ring-buffer LTTB writes when zoom has not been accessed in 10 s,
reducing idle CPU usage
- Use unsafe float64→bytes reinterpretation to eliminate per-element
encoding overhead in the hot broadcast path
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reorder Execute() main stage so the background thread waits on dataSem
(sleeping until the RT thread posts) before doing the socket select().
The socket poll is now non-blocking (timeout=0) since command latency
bounded by UDPS_DATA_WAIT_MS is acceptable for CONNECT/DISCONNECT.
Also force-remove old udpstreamer-webui binary in run.sh before rebuild
so stale embedded assets are never served.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace fragile zoomGuard boolean with userInteracting flag so that
programmatic scale updates (rolling window, resize, fit) never lock
p.xRange. Only genuine mouse drag or scroll-wheel events on the uPlot
canvas set userInteracting=true and allow onZoom to freeze the view.
Also move stale-xRange detection out of the needsRedraw gate so that a
plot whose circular buffer has scrolled past a frozen zoom range
automatically returns to rolling-window mode every frame, fixing the
second bug where data disappeared as the buffer wrapped.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>