initial commit
This commit is contained in:
+164
@@ -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
|
||||
Reference in New Issue
Block a user