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

189 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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](https://plotly.com/javascript/).
```
MARTe2 RT app
│ UDP (binary protocol)
udpstreamer-webui (Go)
│ WebSocket (JSON)
Browser (index.html + Plotly.js)
```
---
## Building
```bash
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
```bash
./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 = 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.
```json
{
"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.
```json
{
"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.