Files
MARTe_IO_Components/Docs/WebUI.md
T
Martino Ferrari e3389f932b FIrs
2026-05-15 17:42:14 +02:00

6.6 KiB
Raw Blame History

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 arraysTimeMode = PacketTime arrays are shown as an expandable group; individual elements (Ch1[0], Ch1[1], …) can be dragged independently.

Adding Plots

  1. Click + Add Plot in the toolbar.
  2. Drag a signal from the sidebar onto a plot panel.
  3. Multiple signals can be overlaid on the same plot.
  4. 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, t and v have N × batchSize entries (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.