6.6 KiB
WebUI Client
The WebUI is a Go binary that acts as a bridge between UDPStreamer and any web browser. It receives UDP packets from UDPStreamer, reassembles fragmented data, and re-publishes decoded signal values over a WebSocket to the browser. The browser renders live plots using Plotly.js.
MARTe2 RT app
│ UDP (binary protocol)
▼
udpstreamer-webui (Go)
│ WebSocket (JSON)
▼
Browser (index.html + Plotly.js)
Building
cd Client/WebUI
go build -o udpstreamer-webui ./...
Requires Go ≥ 1.21. The only external dependency is gorilla/websocket
(declared in go.mod; fetched automatically by go build).
Running
./udpstreamer-webui \
--streamer 127.0.0.1:44500 \ # address:port of the UDPStreamer server
--listen :8080 \ # HTTP / WebSocket listen address
--clientport 44900 # local UDP port for receiving from streamer
Open http://localhost:8080 in any modern browser.
Flags
| Flag | Default | Description |
|---|---|---|
--streamer |
127.0.0.1:44500 |
UDP address of the UDPStreamer DataSource |
--listen |
:8080 |
HTTP server bind address |
--clientport |
44900 |
Local UDP port for receiving data |
Browser UI
Layout
┌─────────────────────────────────────────────────────────┐
│ MARTe2 UDP Streamer ● Streaming Window: [5 s▾] ⏸ │ ← top bar
├──────────┬──────────────────────────────────────────────┤
│ Signals │ Plots [1×1][2×1][2×2]… [+Add] │
│──────────│──────────────────────────────────────────────│
│ Counter │ ┌─────────────────┐ ┌──────────────────┐ │
│ Time │ │ Plot 1 │ │ Plot 2 │ │
│ Sine1 │ │ (drop signals) │ │ (drop signals) │ │
│ Sine2 │ │ │ │ │ │
│ Ch1[1000]│ └─────────────────┘ └──────────────────┘ │
│ Ch2[1000]│ │
└──────────┴──────────────────────────────────────────────┘
Signal Sidebar
Signals received in the CONFIG packet are listed in the sidebar:
- Scalar signals — appear as single draggable items (e.g.
Sine1 · f32). - Temporal arrays — high-frequency burst signals with
TimeMode ≠ PacketTime. Displayed as a single draggable item showing element count:Ch1 · [1000] f32. - Spatial arrays —
TimeMode = PacketTimearrays are shown as an expandable group; individual elements (Ch1[0],Ch1[1], …) can be dragged independently.
Adding Plots
- Click + Add Plot in the toolbar.
- Drag a signal from the sidebar onto a plot panel.
- Multiple signals can be overlaid on the same plot.
- Click the × badge to remove a trace.
Plot Controls
| Control | Action |
|---|---|
| ⏸ / ▶ (per plot) | Pause / resume that plot; paused plots allow zoom and pan |
| ⬇ (per plot) | Export all visible traces to CSV |
| 🗑 (per plot) | Delete the plot |
| ⏸ Pause All (top bar) | Pause all plots simultaneously |
| Window (top bar) | Adjust the rolling time window (1 s – 60 s) |
| Layout buttons | Switch between 1×1, 2×1, 1×2, 2×2, 3×1, … grid layouts |
| Sidebar ← | Collapse the signal list to maximise plot area |
Status LED
| Colour | Meaning |
|---|---|
| Red (solid) | No WebSocket connection to browser |
| Orange (pulsing) | WebSocket connected but no data received in > 1 s |
| Green (pulsing) | Data is being received normally |
Architecture (Go side)
Goroutines
main()
├── hub.Run() ← event loop: register/unregister WS clients, batch data at 30 Hz
├── udpClient.Run() ← reconnects on silence; parses UDP packets; feeds hub.dataCh
└── http.ListenAndServe()
├── GET / ← serves embedded index.html
└── GET /ws ← upgrades to WebSocket; launches per-client read/write pumps
WebSocket Message Format
All messages are JSON. Two types are sent from server to browser:
config message
Sent immediately when a browser client connects (if a CONFIG has been received from UDPStreamer) and whenever UDPStreamer sends a new CONFIG packet.
{
"type": "config",
"signals": [
{
"name": "Sine1",
"typeCode": 8,
"quantType": 3,
"numDimensions": 0,
"numRows": 1,
"numCols": 1,
"rangeMin": -10.0,
"rangeMax": 10.0,
"timeMode": 0,
"samplingRate": 0.0,
"timeSignalIdx": 4294967295,
"unit": "V"
}
]
}
data message
Sent at ≤ 30 Hz, batching all UDP packets received since the last tick. Each signal carries its own time axis to support mixed scalar + temporal-array signals.
{
"type": "data",
"signals": {
"Sine1": { "t": [1747123456.001, 1747123456.002], "v": [3.14, 2.71] },
"Counter": { "t": [1747123456.001, 1747123456.002], "v": [12340, 12341] },
"Ch1": { "t": [1747123456.000, 1747123456.0001, ...], "v": [0.12, 0.13, ...] }
}
}
t— Unix timestamp in seconds (float64) for each sample.v— physical value (after dequantization if applicable).- For temporal arrays,
tandvhaveN × batchSizeentries (up to 2000 per 30 Hz tick after server-side decimation). - For spatial arrays the keys are
"Ch1[0]","Ch1[1]", etc.
Reconnection Behaviour
- UDP reconnect: The Go client reconnects to UDPStreamer automatically after 5 s of silence. This handles MARTe2 restarts transparently.
- WebSocket keepalive: The server sends a WebSocket ping every 30 s. The browser auto-responds; if no pong is received within 10 s the connection is closed and the browser reconnects with exponential backoff (starting at 1 s, capped at 30 s).
- Buffer preservation: Browser-side signal buffers are only reset when the signal layout changes (name, type, or dimensions differ). A reconnect with the same CONFIG keeps existing data visible in the plots.