initial commit

This commit is contained in:
Martino Ferrari
2026-04-11 16:30:18 +02:00
commit dca378b5ef
7 changed files with 929 additions and 0 deletions
+164
View File
@@ -0,0 +1,164 @@
# RMon UI Specification
## Technology
- **Framework**: `egui` + `eframe` (immediate-mode Rust GUI)
- **Render backend**: `glow` (OpenGL 2.1+) — chosen for maximum Linux compatibility
- **Plotting**: `egui_plot` for interactive panels; custom `egui` painter (line strip primitives) for high-throughput paths (>100k points/frame)
- **Async runtime**: `tokio` (runs in a background thread; communicates with egui via `std::sync::mpsc`)
- **SSH tunnel management**: spawns system `ssh` subprocess
## Deployment
Single binary. On Linux, dynamically links only:
- `libGL` (OpenGL driver, always present on any desktop Linux)
- `libX11` / `libxcb` (X11, or Wayland via `libwayland-client` with `wayland` feature)
- `libc` (glibc, standard on all Linux distributions)
On Windows: fully static (links Win32 APIs and ANGLE for OpenGL ES via DirectX).
Pre-built agent binaries for all supported architectures are **embedded in the UI binary** at compile time using `include_bytes!`. This allows the UI to deploy the agent without any extra files.
## Layout
```
┌─────────────────────────────────────────────────────────────────────┐
│ [Connect ▼] [host: myserver] [⏺ Record] [⏹ Stop] [Status: OK] │ ← Toolbar
├────────────────┬────────────────────────────────────────────────────┤
│ Signal Tree │ Plot Panel 1 │ Plot Panel 2 │
│ │ │ │
│ ▼ imu │ [signal A] [signal B] [✕] │ [signal C] [✕] │
│ ▼ accel │ ┌──────────────────────────┐ │ ┌─────────────┐ │
│ accel_x ══╪═►│ time-series plot │ │ │ │ │
│ accel_y │ │ │ │ │ │ │
│ accel_z │ │ ╭─╮ ╭──╮ │ │ │ │ │
│ ▼ gyro │ │ ╯ ╰──╯ ╰─ │ │ │ │ │
│ gyro_x │ │ │ │ └─────────────┘ │
│ gyro_y │ │ ┼────────────────────── │ │ │
│ ▼ temps │ └──────────────────────────┘ │ [+ Add Plot] │
│ inlet │ [cursor A: t=12.3s val=1.2] │ │
│ outlet │ [cursor B: t=15.1s Δt=2.8s] │ │
│ │ [A-B: Δval=-0.3 mean=1.05] │ │
└───────────────┴────────────────────────────────┴───────────────────┘
```
## Connection Dialog
Shown on startup (or via toolbar "Connect" button) when not connected.
Fields:
- **SSH Host**: free text, matched against `~/.ssh/config` Host entries (autocomplete offered)
- **Agent Port**: numeric, default `7891`
- **Agent Config**: path on remote machine, default `~/.rmon/config.toml`
On connect:
1. Detect remote arch via `ssh {host} uname -m`
2. Check / upload agent binary (see `docs/architecture.md` connection flow)
3. Start agent if not running
4. Establish port forward
5. Perform protocol handshake
6. Fetch signal list → populate signal tree
Connection errors are shown inline with a retry button.
## Signal Tree Panel
- Collapsible tree mirroring the `path` field of each `SignalInfo`
- Each leaf shows: label, unit, last value (live-updated), colored dot (source status)
- **Drag-and-drop**: drag a signal leaf onto a plot panel to add it
- **Right-click menu**: "Add to plot 1 / 2 / new plot", "Signal info" (opens info popup), "Start recording", "Stop recording"
- **Search/filter bar** at the top of the panel
- Recording state shown with red ⏺ icon on the signal leaf
## Plot Panels
Any number of plot panels can be open (horizontally tiled by default, resizable/detachable).
### Axes
- X axis: time (absolute UTC or relative to a reference point; toggled in toolbar)
- Y axis: auto-range by default; can be locked manually
- Zoom: scroll wheel (time axis), Ctrl+scroll (Y axis)
- Pan: click-drag on the plot
### Signals in a Plot
- Each signal rendered as a colored line
- Legend at top of plot (click to hide/show individual signals)
- Color is auto-assigned, can be changed via right-click on the legend entry
- Line style (solid/dashed/dotted) and width configurable per signal
### Cursors
- Add cursors via toolbar button or right-click on plot → "Add cursor"
- Drag to position; snaps to nearest sample if within threshold
- Measurement bar below the plot shows:
- Per cursor: timestamp, value for each visible signal
- Between two cursors: Δt, Δvalue, mean, min, max over the interval
### Math Signals
- Right-click plot → "Add math signal"
- Expression editor (simple formula: `a + b`, `a * 2.0`, `a - b`, etc. where `a`, `b` are signal IDs)
- Math signals appear in the legend with an `f(x)` icon and can be added to other plots
### High-Throughput Rendering
When a signal has more points than pixels in the X direction, the renderer decimates using **min-max downsampling** (preserves peaks/troughs visually). This runs on the CPU in `plot_panel.rs` before passing vertices to egui's painter.
## Toolbar
- **Connect / Disconnect** dropdown (shows current host or "Not connected")
- **Time range** selector: presets (last 10s / 1min / 10min / 1h) or custom range picker
- **Time display** toggle: absolute UTC vs relative
- **Record** button: opens signal selection dialog → starts recording for selected signals
- **Status indicator**: green = connected, yellow = reconnecting, red = disconnected
## Keyboard Shortcuts
| Key | Action |
|-----|--------|
| `Space` | Pause / resume live scrolling |
| `R` | Reset all plot zoom/pan to live view |
| `C` | Add cursor to focused plot |
| `Del` | Remove selected cursor |
| `Ctrl+N` | Add new plot panel |
| `Ctrl+W` | Close focused plot panel |
| `Ctrl+F` | Focus signal tree search |
| `Ctrl+S` | Save current layout to file |
## Session Persistence
On clean exit, the UI saves the current session to `~/.config/rmon/last_session.toml`:
- Connected host alias
- Open plot panels and their signal assignments
- Cursor positions
- Time range and zoom state
On next launch with the same host, it offers to restore the session.
## State Machine (connection)
```
Disconnected
│ user clicks Connect
Deploying (copying/verifying agent binary)
│ agent ready
Tunneling (SSH port-forward process running)
│ port open
Handshaking (TCP open, sent Handshake, awaiting HandshakeAck)
│ accepted
Connected (normal operation, DataBatch messages flowing)
│ tunnel drops / error
Reconnecting (exponential backoff, max 30s, reuses same tunnel if still up)
│ max retries exceeded
Disconnected
```
## Async / UI Thread Boundary
- `tokio` runtime runs in a dedicated OS thread
- The egui render loop runs on the main thread (required by most platform window systems)
- Communication: `std::sync::mpsc::channel` — the tokio tasks push `UiEvent` variants (DataBatch, SignalList, Status, Error) to the UI; the UI pushes `Command` variants (Subscribe, QueryHistory, StartRecording) to tokio
- `eframe::App::update()` drains the incoming event channel each frame before rendering