Rename project from xserial to pipeview

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-06-12 22:17:40 +08:00
parent fd680858f6
commit 8caf7d6d62
64 changed files with 314 additions and 314 deletions

View File

@@ -8,25 +8,25 @@
## Project Structure ## Project Structure
`xserial` is a Rust workspace. The root `Cargo.toml` defines four crates in `crates/`, with dependencies flowing: `pipeview` is a Rust workspace. The root `Cargo.toml` defines four crates in `crates/`, with dependencies flowing:
``` ```
xserial-core (no internal deps — transport, framing, protocol, pipeline) pipeview-core (no internal deps — transport, framing, protocol, pipeline)
xserial-client (depends on xserial-core — sessions, history, commands, Lua) pipeview-client (depends on pipeview-core — sessions, history, commands, Lua)
↑ ↑ ↑ ↑
xserial-gui xserial-tui pipeview-gui pipeview-tui
(both depend on xserial-core AND xserial-client) (both depend on pipeview-core AND pipeview-client)
``` ```
| Crate | Type | What goes here | | Crate | Type | What goes here |
|-------|------|---------------| |-------|------|---------------|
| `xserial-core` | library (`src/lib.rs`) | `transport/`, `frame/`, `protocol/`, `pipeline.rs` — protocol and I/O. Integration tests: `tests/pipeline.rs`. | | `pipeview-core` | library (`src/lib.rs`) | `transport/`, `frame/`, `protocol/`, `pipeline.rs` — protocol and I/O. Integration tests: `tests/pipeline.rs`. |
| `xserial-client` | library (`src/lib.rs`) | `session.rs`, `manager.rs`, `config.rs`, `history.rs`, `lua/` — state management and Lua bindings. Integration tests: `tests/session_lifecycle.rs`, `tests/lua_tests.rs`. | | `pipeview-client` | library (`src/lib.rs`) | `session.rs`, `manager.rs`, `config.rs`, `history.rs`, `lua/` — state management and Lua bindings. Integration tests: `tests/session_lifecycle.rs`, `tests/lua_tests.rs`. |
| `xserial-gui` | binary (`src/main.rs`) | egui/eframe app. Panels in `src/panels/`. Font helpers in `src/ui_fonts.rs`. Profiling in `src/perf.rs`. | | `pipeview-gui` | binary (`src/main.rs`) | egui/eframe app. Panels in `src/panels/`. Font helpers in `src/ui_fonts.rs`. Profiling in `src/perf.rs`. |
| `xserial-tui` | binary (`src/main.rs`) | ratatui/crossterm app. **Still a placeholder** — zero tests, not at feature parity with GUI. | | `pipeview-tui` | binary (`src/main.rs`) | ratatui/crossterm app. **Still a placeholder** — zero tests, not at feature parity with GUI. |
**Module boundaries**: transport/protocol → `xserial-core`. Session/Lua → `xserial-client`. UI state → `xserial-gui` or `xserial-tui`. Never put I/O logic in the UI crates, never put UI state in the client crate. **Module boundaries**: transport/protocol → `pipeview-core`. Session/Lua → `pipeview-client`. UI state → `pipeview-gui` or `pipeview-tui`. Never put I/O logic in the UI crates, never put UI state in the client crate.
## Build, Test, and Development Commands ## Build, Test, and Development Commands
@@ -40,21 +40,21 @@ cargo clippy --workspace --all-targets -- -D warnings # lint gate
**Run specific tests:** **Run specific tests:**
```bash ```bash
cargo test -p xserial-core -- tcp_line_text_utf8 cargo test -p pipeview-core -- tcp_line_text_utf8
cargo test -p xserial-client -- session_echo_send_and_read cargo test -p pipeview-client -- session_echo_send_and_read
cargo test -p xserial-core -- --nocapture # show test output cargo test -p pipeview-core -- --nocapture # show test output
# Integration tests only # Integration tests only
cargo test -p xserial-core --test pipeline cargo test -p pipeview-core --test pipeline
cargo test -p xserial-client --test session_lifecycle cargo test -p pipeview-client --test session_lifecycle
cargo test -p xserial-client --test lua_tests cargo test -p pipeview-client --test lua_tests
``` ```
**Launch:** **Launch:**
```bash ```bash
cargo run -p xserial-gui cargo run -p pipeview-gui
cargo run -p xserial-tui cargo run -p pipeview-tui
``` ```
## Environment & Configuration ## Environment & Configuration
@@ -62,8 +62,8 @@ cargo run -p xserial-tui
### Tracing (all entrypoints) ### Tracing (all entrypoints)
```bash ```bash
RUST_LOG=info cargo run -p xserial-gui RUST_LOG=info cargo run -p pipeview-gui
RUST_LOG=xserial_gui::perf=debug cargo run -p xserial-gui RUST_LOG=pipeview_gui::perf=debug cargo run -p pipeview-gui
``` ```
`tracing_subscriber::EnvFilter::from_default_env()` reads `RUST_LOG`. The workspace dep `tracing-subscriber` has `features = ["env-filter"]`. `tracing_subscriber::EnvFilter::from_default_env()` reads `RUST_LOG`. The workspace dep `tracing-subscriber` has `features = ["env-filter"]`.
@@ -71,11 +71,11 @@ RUST_LOG=xserial_gui::perf=debug cargo run -p xserial-gui
### GUI Profiling ### GUI Profiling
```bash ```bash
RUST_LOG=xserial_gui::perf=info XSERIAL_GUI_PROFILE=1 cargo run -p xserial-gui RUST_LOG=pipeview_gui::perf=info XSERIAL_GUI_PROFILE=1 cargo run -p pipeview-gui
XSERIAL_GUI_PROFILE_INTERVAL_MS=500 cargo run -p xserial-gui # custom interval (default 1s) XSERIAL_GUI_PROFILE_INTERVAL_MS=500 cargo run -p pipeview-gui # custom interval (default 1s)
``` ```
Profiling logs go to target `xserial_gui::perf`. Profiling logs go to target `pipeview_gui::perf`.
### State & Config File Paths (runtime, not compile-time) ### State & Config File Paths (runtime, not compile-time)
@@ -83,9 +83,9 @@ Uses `env::consts::OS` + env vars — no `cfg(target_os)` gating for path resolu
| Platform | Root config path | | Platform | Root config path |
|----------|-----------------| |----------|-----------------|
| Linux | `$XDG_CONFIG_HOME/xserial/` or `~/.config/xserial/` | | Linux | `$XDG_CONFIG_HOME/pipeview/` or `~/.config/pipeview/` |
| macOS | `~/Library/Application Support/xserial/` | | macOS | `~/Library/Application Support/pipeview/` |
| Windows | `%APPDATA%\xserial\` | | Windows | `%APPDATA%\pipeview\` |
State files: `gui-state.json`, `tui-state.json`, `font-settings.json`. State files: `gui-state.json`, `tui-state.json`, `font-settings.json`.
@@ -120,9 +120,9 @@ Standard Rust conventions (`cargo fmt`). No crate-level lint attrs, no `[lints]`
- **No feature flags** — zero `[features]` in any `Cargo.toml`. No `#[cfg(feature)]` in any source. - **No feature flags** — zero `[features]` in any `Cargo.toml`. No `#[cfg(feature)]` in any source.
- **No build scripts** — zero `build.rs` files. No codegen. No `include!`/`include_str!`/`include_bytes!`. - **No build scripts** — zero `build.rs` files. No codegen. No `include!`/`include_str!`/`include_bytes!`.
- **All `unsafe` is test-only** — constructing noop wakers for poll-based unit tests in `transport/`. No non-test `unsafe` anywhere. - **All `unsafe` is test-only** — constructing noop wakers for poll-based unit tests in `transport/`. No non-test `unsafe` anywhere.
- **`xserial-tui` is a stub** — no tests, minimal implementation. GUI is the primary target. - **`pipeview-tui` is a stub** — no tests, minimal implementation. GUI is the primary target.
- **Platform font directories** use `#[cfg(target_os)]` in `ui_fonts.rs` (three blocks: Windows, macOS, Linux/BSD). - **Platform font directories** use `#[cfg(target_os)]` in `ui_fonts.rs` (three blocks: Windows, macOS, Linux/BSD).
- **`tokio` features differ by build**: `xserial-client` uses `["sync", "time"]` for production, `["full"]` for dev-dependencies (tests need net/IO). - **`tokio` features differ by build**: `pipeview-client` uses `["sync", "time"]` for production, `["full"]` for dev-dependencies (tests need net/IO).
## Commit & PR Guidelines ## Commit & PR Guidelines

136
Cargo.lock generated
View File

@@ -3262,6 +3262,74 @@ dependencies = [
"futures-io", "futures-io",
] ]
[[package]]
name = "pipeview-client"
version = "0.1.0"
dependencies = [
"mlua",
"pipeview-core",
"serde",
"serde_json",
"thiserror 2.0.18",
"tokio",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "pipeview-core"
version = "0.1.0"
dependencies = [
"async-trait",
"bytes",
"hex",
"nom 8.0.0",
"serde",
"serde_json",
"serialport",
"thiserror 2.0.18",
"tokio",
"tokio-serial",
"tracing",
]
[[package]]
name = "pipeview-gui"
version = "0.1.0"
dependencies = [
"eframe",
"egui",
"egui_plot",
"hex",
"pipeview-client",
"pipeview-core",
"serde",
"serde_json",
"tokio",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "pipeview-tui"
version = "0.1.0"
dependencies = [
"clap",
"crossterm 0.28.1",
"hex",
"image",
"mlua",
"pipeview-client",
"pipeview-core",
"ratatui",
"serde",
"serde_json",
"tokio",
"tracing",
"tracing-appender",
"tracing-subscriber",
]
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.33" version = "0.3.33"
@@ -5750,74 +5818,6 @@ version = "0.8.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f"
[[package]]
name = "xserial-client"
version = "0.1.0"
dependencies = [
"mlua",
"serde",
"serde_json",
"thiserror 2.0.18",
"tokio",
"tracing",
"tracing-subscriber",
"xserial-core",
]
[[package]]
name = "xserial-core"
version = "0.1.0"
dependencies = [
"async-trait",
"bytes",
"hex",
"nom 8.0.0",
"serde",
"serde_json",
"serialport",
"thiserror 2.0.18",
"tokio",
"tokio-serial",
"tracing",
]
[[package]]
name = "xserial-gui"
version = "0.1.0"
dependencies = [
"eframe",
"egui",
"egui_plot",
"hex",
"serde",
"serde_json",
"tokio",
"tracing",
"tracing-subscriber",
"xserial-client",
"xserial-core",
]
[[package]]
name = "xserial-tui"
version = "0.1.0"
dependencies = [
"clap",
"crossterm 0.28.1",
"hex",
"image",
"mlua",
"ratatui",
"serde",
"serde_json",
"tokio",
"tracing",
"tracing-appender",
"tracing-subscriber",
"xserial-client",
"xserial-core",
]
[[package]] [[package]]
name = "yoke" name = "yoke"
version = "0.8.2" version = "0.8.2"

View File

@@ -1,10 +1,10 @@
[workspace] [workspace]
resolver = "2" resolver = "2"
members = [ members = [
"crates/xserial-core", "crates/pipeview-core",
"crates/xserial-client", "crates/pipeview-client",
"crates/xserial-tui", "crates/pipeview-tui",
"crates/xserial-gui", "crates/pipeview-gui",
] ]
[workspace.dependencies] [workspace.dependencies]

View File

@@ -1,4 +1,4 @@
# xserial # pipeview
**跨平台串口 / TCP / UDP 数据观测工具** — 可配置分帧、协议解码、多会话管理、实时波形绘图,单二进制零依赖。 **跨平台串口 / TCP / UDP 数据观测工具** — 可配置分帧、协议解码、多会话管理、实时波形绘图,单二进制零依赖。
@@ -89,8 +89,8 @@
- **自定义分帧器** — 实现 `feed(bytes)``flush()``reset()``pending_len()` 四个函数 - **自定义分帧器** — 实现 `feed(bytes)``flush()``reset()``pending_len()` 四个函数
- **自定义解码器** — 实现 `decode(frame)` 函数,返回 text/hex/plot/binary 四种类型 - **自定义解码器** — 实现 `decode(frame)` 函数,返回 text/hex/plot/binary 四种类型
- **会话 API** — `xserial.open()` 创建 Session、`session:on_data()` 事件回调、`session:send()` 发送数据 - **会话 API** — `pipeview.open()` 创建 Session、`session:on_data()` 事件回调、`session:send()` 发送数据
- **工具函数** — `xserial.list_ports()``xserial.sleep(ms)``xserial.poll(limit)``xserial.log(msg)` - **工具函数** — `pipeview.list_ports()``pipeview.sleep(ms)``pipeview.poll(limit)``pipeview.log(msg)`
### 快捷键 ### 快捷键
@@ -125,11 +125,11 @@
```bash ```bash
# 克隆项目 # 克隆项目
git clone https://github.com/your-org/xserial.git git clone https://github.com/your-org/pipeview.git
cd xserial cd pipeview
# 编译运行 # 编译运行
cargo run -p xserial-gui cargo run -p pipeview-gui
# 运行测试 # 运行测试
cargo test --workspace # ~308 个测试 cargo test --workspace # ~308 个测试
@@ -139,9 +139,9 @@ cargo clippy --workspace --all-targets -- -D warnings
### 发布构建 ### 发布构建
```bash ```bash
cargo build -p xserial-gui --release cargo build -p pipeview-gui --release
# 二进制位于 target/release/xserial-gui (Linux/macOS) # 二进制位于 target/release/pipeview-gui (Linux/macOS)
# 或 target/release/xserial-gui.exe (Windows) # 或 target/release/pipeview-gui.exe (Windows)
``` ```
--- ---
@@ -168,7 +168,7 @@ Listening on 127.0.0.1:8091, waiting for connections...
### 步骤 2配置 Session ### 步骤 2配置 Session
xserial-gui 中创建 Session pipeview-gui 中创建 Session
| 配置项 | 值 | | 配置项 | 值 |
|--------|-----| |--------|-----|
@@ -277,23 +277,23 @@ return {
``` ```
┌──────────────────────────────────────────────────┐ ┌──────────────────────────────────────────────────┐
xserial-gui (egui) xserial-tui (ratatui) │ pipeview-gui (egui) pipeview-tui (ratatui) │
├──────────────────────────────────────────────────┤ ├──────────────────────────────────────────────────┤
xserial-client │ pipeview-client │
│ SessionManager · Session · Config · History │ │ SessionManager · Session · Config · History │
│ Lua Runtime (mlua / LuaJIT) │ │ Lua Runtime (mlua / LuaJIT) │
├──────────────────────────────────────────────────┤ ├──────────────────────────────────────────────────┤
xserial-core │ pipeview-core │
│ Transport ──▶ Frame ──▶ Protocol ──▶ Pipeline │ │ Transport ──▶ Frame ──▶ Protocol ──▶ Pipeline │
└──────────────────────────────────────────────────┘ └──────────────────────────────────────────────────┘
``` ```
| Crate | 类型 | 职责 | | Crate | 类型 | 职责 |
|-------|------|------| |-------|------|------|
| `xserial-core` | library | 传输层Serial/TCP/UDP、分帧器Line/Fixed/Length/COBS/Mixed/Lua、协议解码器Text/Hex/Plot、MultiPipeline | | `pipeview-core` | library | 传输层Serial/TCP/UDP、分帧器Line/Fixed/Length/COBS/Mixed/Lua、协议解码器Text/Hex/Plot、MultiPipeline |
| `xserial-client` | library | Session 生命周期管理、SessionManager、事件广播tokio broadcast、RingBuffer 历史、Lua 运行时及会话 API | | `pipeview-client` | library | Session 生命周期管理、SessionManager、事件广播tokio broadcast、RingBuffer 历史、Lua 运行时及会话 API |
| `xserial-gui` | binary | egui 桌面应用,包含 sidebar/config/console/text/hex/plot 面板、键盘快捷键、字体管理、性能分析 | | `pipeview-gui` | binary | egui 桌面应用,包含 sidebar/config/console/text/hex/plot 面板、键盘快捷键、字体管理、性能分析 |
| `xserial-tui` | binary | ratatui 终端应用(功能未对齐 GUI仍在开发中 | | `pipeview-tui` | binary | ratatui 终端应用(功能未对齐 GUI仍在开发中 |
**依赖方向:** `core ← client ← {gui, tui}` **依赖方向:** `core ← client ← {gui, tui}`
@@ -316,9 +316,9 @@ GUI 状态自动保存,路径遵循各平台规范:
| 平台 | 路径 | | 平台 | 路径 |
|------|------| |------|------|
| Linux | `$XDG_CONFIG_HOME/xserial/gui-state.json``~/.config/xserial/gui-state.json` | | Linux | `$XDG_CONFIG_HOME/pipeview/gui-state.json``~/.config/pipeview/gui-state.json` |
| macOS | `~/Library/Application Support/xserial/gui-state.json` | | macOS | `~/Library/Application Support/pipeview/gui-state.json` |
| Windows | `%APPDATA%\xserial\gui-state.json` | | Windows | `%APPDATA%\pipeview\gui-state.json` |
持久化的内容包括Session 配置(传输参数、管线设置)、日志开关及路径、活动标签页、显示选项。 持久化的内容包括Session 配置(传输参数、管线设置)、日志开关及路径、活动标签页、显示选项。
@@ -343,8 +343,8 @@ python tools/test_drone.py --rate 10 --port 8092
### 性能分析 ### 性能分析
```bash ```bash
RUST_LOG=xserial_gui::perf=info XSERIAL_GUI_PROFILE=1 cargo run -p xserial-gui RUST_LOG=pipeview_gui::perf=info XSERIAL_GUI_PROFILE=1 cargo run -p pipeview-gui
XSERIAL_GUI_PROFILE_INTERVAL_MS=500 cargo run -p xserial-gui XSERIAL_GUI_PROFILE_INTERVAL_MS=500 cargo run -p pipeview-gui
``` ```
输出每帧的耗时、事件 drain 耗时、text/hex/plot 渲染耗时、plot 点数统计。 输出每帧的耗时、事件 drain 耗时、text/hex/plot 渲染耗时、plot 点数统计。
@@ -352,8 +352,8 @@ XSERIAL_GUI_PROFILE_INTERVAL_MS=500 cargo run -p xserial-gui
### 日志 ### 日志
```bash ```bash
RUST_LOG=info cargo run -p xserial-gui # 应用日志 RUST_LOG=info cargo run -p pipeview-gui # 应用日志
RUST_LOG=xserial_gui=debug cargo run -p xserial-gui # 详细日志 RUST_LOG=pipeview_gui=debug cargo run -p pipeview-gui # 详细日志
``` ```
使用 `tracing-subscriber` + `RUST_LOG` 环境变量控制。 使用 `tracing-subscriber` + `RUST_LOG` 环境变量控制。
@@ -362,10 +362,10 @@ RUST_LOG=xserial_gui=debug cargo run -p xserial-gui # 详细日志
``` ```
crates/ crates/
xserial-core/ # 传输、分帧、协议 pipeview-core/ # 传输、分帧、协议
xserial-client/ # 会话管理、Lua 运行时 pipeview-client/ # 会话管理、Lua 运行时
xserial-gui/ # egui 桌面应用 pipeview-gui/ # egui 桌面应用
xserial-tui/ # ratatui 终端应用 pipeview-tui/ # ratatui 终端应用
examples/ # Lua 脚本示例 examples/ # Lua 脚本示例
drone_plot.lua # 飞控遥测波形解码器 drone_plot.lua # 飞控遥测波形解码器
drone_text.lua # 飞控遥测文本解码器 drone_text.lua # 飞控遥测文本解码器

View File

@@ -1,4 +1,4 @@
# xserial # pipeview
**Cross-platform serial / TCP / UDP data inspection tool** with configurable framing, protocol decoding, multi-session management, and real-time waveform plotting — all in a single binary. **Cross-platform serial / TCP / UDP data inspection tool** with configurable framing, protocol decoding, multi-session management, and real-time waveform plotting — all in a single binary.
@@ -89,8 +89,8 @@ Built-in LuaJIT runtime:
- **Custom framers** — implement `feed(bytes)`, `flush()`, `reset()`, `pending_len()` - **Custom framers** — implement `feed(bytes)`, `flush()`, `reset()`, `pending_len()`
- **Custom decoders** — implement `decode(frame)`, return text/hex/plot/binary - **Custom decoders** — implement `decode(frame)`, return text/hex/plot/binary
- **Session API** — `xserial.open()` to create sessions, `session:on_data()` for event callbacks, `session:send()` to transmit data - **Session API** — `pipeview.open()` to create sessions, `session:on_data()` for event callbacks, `session:send()` to transmit data
- **Utilities** — `xserial.list_ports()`, `xserial.sleep(ms)`, `xserial.poll(limit)`, `xserial.log(msg)` - **Utilities** — `pipeview.list_ports()`, `pipeview.sleep(ms)`, `pipeview.poll(limit)`, `pipeview.log(msg)`
### Keyboard Shortcuts ### Keyboard Shortcuts
@@ -124,10 +124,10 @@ Built-in LuaJIT runtime:
### Build & Run ### Build & Run
```bash ```bash
git clone https://github.com/your-org/xserial.git git clone https://github.com/your-org/pipeview.git
cd xserial cd pipeview
cargo run -p xserial-gui cargo run -p pipeview-gui
# Run tests # Run tests
cargo test --workspace # ~308 tests cargo test --workspace # ~308 tests
@@ -137,9 +137,9 @@ cargo clippy --workspace --all-targets -- -D warnings
### Release Build ### Release Build
```bash ```bash
cargo build -p xserial-gui --release cargo build -p pipeview-gui --release
# Binary: target/release/xserial-gui (Linux/macOS) # Binary: target/release/pipeview-gui (Linux/macOS)
# target/release/xserial-gui.exe (Windows) # target/release/pipeview-gui.exe (Windows)
``` ```
--- ---
@@ -160,7 +160,7 @@ python tools/test_drone.py --rate 10 --port 8091
### Step 2: Configure the session ### Step 2: Configure the session
In xserial-gui, create a session with two pipelines: In pipeview-gui, create a session with two pipelines:
| Setting | Value | | Setting | Value |
|---------|-------| |---------|-------|
@@ -265,23 +265,23 @@ More examples in `examples/`.
``` ```
┌──────────────────────────────────────────────────┐ ┌──────────────────────────────────────────────────┐
xserial-gui (egui) xserial-tui (ratatui) │ pipeview-gui (egui) pipeview-tui (ratatui) │
├──────────────────────────────────────────────────┤ ├──────────────────────────────────────────────────┤
xserial-client │ pipeview-client │
│ SessionManager · Session · Config · History │ │ SessionManager · Session · Config · History │
│ Lua Runtime (mlua / LuaJIT) │ │ Lua Runtime (mlua / LuaJIT) │
├──────────────────────────────────────────────────┤ ├──────────────────────────────────────────────────┤
xserial-core │ pipeview-core │
│ Transport ──▶ Frame ──▶ Protocol ──▶ Pipeline │ │ Transport ──▶ Frame ──▶ Protocol ──▶ Pipeline │
└──────────────────────────────────────────────────┘ └──────────────────────────────────────────────────┘
``` ```
| Crate | Type | Purpose | | Crate | Type | Purpose |
|-------|------|---------| |-------|------|---------|
| `xserial-core` | library | Transport (Serial/TCP/UDP), framers (Line/Fixed/Length/COBS/Mixed/Lua), decoders (Text/Hex/Plot), MultiPipeline | | `pipeview-core` | library | Transport (Serial/TCP/UDP), framers (Line/Fixed/Length/COBS/Mixed/Lua), decoders (Text/Hex/Plot), MultiPipeline |
| `xserial-client` | library | Session lifecycle, SessionManager, event broadcast (tokio broadcast), RingBuffer history, Lua runtime & session API | | `pipeview-client` | library | Session lifecycle, SessionManager, event broadcast (tokio broadcast), RingBuffer history, Lua runtime & session API |
| `xserial-gui` | binary | egui desktop app: sidebar, config, console, text/hex/plot panels, keyboard shortcuts, font management, profiling | | `pipeview-gui` | binary | egui desktop app: sidebar, config, console, text/hex/plot panels, keyboard shortcuts, font management, profiling |
| `xserial-tui` | binary | ratatui terminal app (feature-incomplete, under development) | | `pipeview-tui` | binary | ratatui terminal app (feature-incomplete, under development) |
**Dependency flow:** `core ← client ← {gui, tui}` **Dependency flow:** `core ← client ← {gui, tui}`
@@ -304,9 +304,9 @@ GUI state is saved automatically to platform-standard locations:
| Platform | Path | | Platform | Path |
|----------|------| |----------|------|
| Linux | `$XDG_CONFIG_HOME/xserial/gui-state.json` or `~/.config/xserial/gui-state.json` | | Linux | `$XDG_CONFIG_HOME/pipeview/gui-state.json` or `~/.config/pipeview/gui-state.json` |
| macOS | `~/Library/Application Support/xserial/gui-state.json` | | macOS | `~/Library/Application Support/pipeview/gui-state.json` |
| Windows | `%APPDATA%\xserial\gui-state.json` | | Windows | `%APPDATA%\pipeview\gui-state.json` |
Persisted data includes: session configurations (transport, pipelines), log settings, active tab, and display options. Persisted data includes: session configurations (transport, pipelines), log settings, active tab, and display options.
@@ -331,25 +331,25 @@ python tools/test_drone.py --rate 10 --port 8092
### Profiling ### Profiling
```bash ```bash
RUST_LOG=xserial_gui::perf=info XSERIAL_GUI_PROFILE=1 cargo run -p xserial-gui RUST_LOG=pipeview_gui::perf=info XSERIAL_GUI_PROFILE=1 cargo run -p pipeview-gui
XSERIAL_GUI_PROFILE_INTERVAL_MS=500 cargo run -p xserial-gui XSERIAL_GUI_PROFILE_INTERVAL_MS=500 cargo run -p pipeview-gui
``` ```
### Tracing ### Tracing
```bash ```bash
RUST_LOG=info cargo run -p xserial-gui RUST_LOG=info cargo run -p pipeview-gui
RUST_LOG=xserial_gui=debug cargo run -p xserial-gui RUST_LOG=pipeview_gui=debug cargo run -p pipeview-gui
``` ```
### Project Structure ### Project Structure
``` ```
crates/ crates/
xserial-core/ # Transport, framing, protocol pipeview-core/ # Transport, framing, protocol
xserial-client/ # Session management, Lua runtime pipeview-client/ # Session management, Lua runtime
xserial-gui/ # egui desktop application pipeview-gui/ # egui desktop application
xserial-tui/ # ratatui terminal application pipeview-tui/ # ratatui terminal application
examples/ # Lua script examples examples/ # Lua script examples
drone_plot.lua # Drone telemetry plot decoder drone_plot.lua # Drone telemetry plot decoder
drone_text.lua # Drone telemetry text decoder drone_text.lua # Drone telemetry text decoder

View File

@@ -1,10 +1,10 @@
[package] [package]
name = "xserial-client" name = "pipeview-client"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
xserial-core = { path = "../xserial-core" } pipeview-core = { path = "../pipeview-core" }
tokio = { workspace = true, features = ["sync", "time"] } tokio = { workspace = true, features = ["sync", "time"] }
tracing = { workspace = true } tracing = { workspace = true }
serde = { workspace = true } serde = { workspace = true }

View File

@@ -1,5 +1,5 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use xserial_core::frame::{ use pipeview_core::frame::{
Endian, Framer, Endian, Framer,
cobs::CobsFramer, cobs::CobsFramer,
fixed::FixedLengthFramer, fixed::FixedLengthFramer,
@@ -7,14 +7,14 @@ use xserial_core::frame::{
line::{LineConfig, LineFramer}, line::{LineConfig, LineFramer},
mixed::{MixedTextPlotConfig as MixedFramerConfig, MixedTextPlotFramer}, mixed::{MixedTextPlotConfig as MixedFramerConfig, MixedTextPlotFramer},
}; };
use xserial_core::protocol::{ use pipeview_core::protocol::{
ProtocolDecoder, ProtocolDecoder,
hex::{HexConfig, HexDecoder}, hex::{HexConfig, HexDecoder},
mixed::{MixedTextPlotConfig as MixedDecoderConfig, MixedTextPlotDecoder}, mixed::{MixedTextPlotConfig as MixedDecoderConfig, MixedTextPlotDecoder},
plot::{PlotConfig, PlotDecoder, PlotFormat, SampleType}, plot::{PlotConfig, PlotDecoder, PlotFormat, SampleType},
text::{TextDecoder, TextEncoding}, text::{TextDecoder, TextEncoding},
}; };
use xserial_core::transport::TransportConfig; use pipeview_core::transport::TransportConfig;
use crate::error::Result; use crate::error::Result;
use crate::lua::codec::{LuaDecoder, LuaFramer}; use crate::lua::codec::{LuaDecoder, LuaFramer};
@@ -229,10 +229,10 @@ impl Default for SessionConfig {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use xserial_core::protocol::Endian; use pipeview_core::protocol::Endian;
use xserial_core::protocol::plot::{PlotFormat, SampleType}; use pipeview_core::protocol::plot::{PlotFormat, SampleType};
use xserial_core::protocol::text::TextEncoding; use pipeview_core::protocol::text::TextEncoding;
use xserial_core::transport::TransportConfig; use pipeview_core::transport::TransportConfig;
#[test] #[test]
fn framer_line_serde_roundtrip() { fn framer_line_serde_roundtrip() {

View File

@@ -1,4 +1,4 @@
use xserial_core::protocol::DecodedData; use pipeview_core::protocol::DecodedData;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DecodedEntry { pub struct DecodedEntry {

View File

@@ -3,9 +3,9 @@ use std::sync::Mutex;
use mlua::{Function, Lua, RegistryKey, Table, Value}; use mlua::{Function, Lua, RegistryKey, Table, Value};
use tracing::warn; use tracing::warn;
use xserial_core::frame::Framer; use pipeview_core::frame::Framer;
use xserial_core::protocol::plot::{PlotFormat, PlotFrame, SampleType}; use pipeview_core::protocol::plot::{PlotFormat, PlotFrame, SampleType};
use xserial_core::protocol::{DecodedData, ProtocolDecoder}; use pipeview_core::protocol::{DecodedData, ProtocolDecoder};
use crate::error::{Error, Result}; use crate::error::{Error, Result};
@@ -297,7 +297,7 @@ mod tests {
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
.unwrap() .unwrap()
.as_nanos(); .as_nanos();
let path = std::env::temp_dir().join(format!("xserial_{name}_{nonce}.lua")); let path = std::env::temp_dir().join(format!("pipeview_{name}_{nonce}.lua"));
fs::write(&path, script).unwrap(); fs::write(&path, script).unwrap();
path path
} }

View File

@@ -81,9 +81,9 @@ pub fn register(lua: &Lua) -> LuaResult<()> {
pub fn register_with_manager(lua: &Lua, manager: SessionManager) -> LuaResult<()> { pub fn register_with_manager(lua: &Lua, manager: SessionManager) -> LuaResult<()> {
let runtime = LuaRuntime::new(manager); let runtime = LuaRuntime::new(manager);
let xserial = lua.create_table()?; let pipeview = lua.create_table()?;
xserial.set("open", { pipeview.set("open", {
let runtime = runtime.clone(); let runtime = runtime.clone();
lua.create_async_function(move |lua, config: Table| { lua.create_async_function(move |lua, config: Table| {
let runtime = runtime.clone(); let runtime = runtime.clone();
@@ -96,15 +96,15 @@ pub fn register_with_manager(lua: &Lua, manager: SessionManager) -> LuaResult<()
})? })?
})?; })?;
xserial.set( pipeview.set(
"list_ports", "list_ports",
lua.create_function(|_, ()| { lua.create_function(|_, ()| {
let ports = xserial_core::transport::serial::SerialTransport::list_ports(); let ports = pipeview_core::transport::serial::SerialTransport::list_ports();
Ok(ports.into_iter().map(|p| p.port_name).collect::<Vec<_>>()) Ok(ports.into_iter().map(|p| p.port_name).collect::<Vec<_>>())
})?, })?,
)?; )?;
xserial.set("sleep", { pipeview.set("sleep", {
let runtime = runtime.clone(); let runtime = runtime.clone();
lua.create_async_function(move |lua, ms: u64| { lua.create_async_function(move |lua, ms: u64| {
let runtime = runtime.clone(); let runtime = runtime.clone();
@@ -116,7 +116,7 @@ pub fn register_with_manager(lua: &Lua, manager: SessionManager) -> LuaResult<()
})? })?
})?; })?;
xserial.set("poll", { pipeview.set("poll", {
let runtime = runtime.clone(); let runtime = runtime.clone();
lua.create_async_function(move |lua, limit_per_session: Option<usize>| { lua.create_async_function(move |lua, limit_per_session: Option<usize>| {
let runtime = runtime.clone(); let runtime = runtime.clone();
@@ -124,7 +124,7 @@ pub fn register_with_manager(lua: &Lua, manager: SessionManager) -> LuaResult<()
})? })?
})?; })?;
xserial.set( pipeview.set(
"log", "log",
lua.create_function(|_, msg: String| { lua.create_function(|_, msg: String| {
tracing::info!("[lua] {}", msg); tracing::info!("[lua] {}", msg);
@@ -132,7 +132,7 @@ pub fn register_with_manager(lua: &Lua, manager: SessionManager) -> LuaResult<()
})?, })?,
)?; )?;
lua.globals().set("xserial", xserial)?; lua.globals().set("pipeview", pipeview)?;
Ok(()) Ok(())
} }
@@ -146,9 +146,9 @@ mod tests {
let lua = Lua::new(); let lua = Lua::new();
register(&lua).unwrap(); register(&lua).unwrap();
let xserial: Table = lua.globals().get("xserial").unwrap(); let pipeview: Table = lua.globals().get("pipeview").unwrap();
for name in ["open", "list_ports", "sleep", "poll", "log"] { for name in ["open", "list_ports", "sleep", "poll", "log"] {
let value: Value = xserial.get(name).unwrap(); let value: Value = pipeview.get(name).unwrap();
assert!( assert!(
matches!(value, Value::Function(_)), matches!(value, Value::Function(_)),
"{name} should be a function" "{name} should be a function"
@@ -162,8 +162,8 @@ mod tests {
let manager = SessionManager::new(); let manager = SessionManager::new();
register_with_manager(&lua, manager.clone()).unwrap(); register_with_manager(&lua, manager.clone()).unwrap();
let xserial: Table = lua.globals().get("xserial").unwrap(); let pipeview: Table = lua.globals().get("pipeview").unwrap();
let open: Value = xserial.get("open").unwrap(); let open: Value = pipeview.get("open").unwrap();
assert!(matches!(open, Value::Function(_))); assert!(matches!(open, Value::Function(_)));
assert_eq!(manager.count(), 0); assert_eq!(manager.count(), 0);
} }

View File

@@ -8,7 +8,7 @@ use std::time::Duration;
use mlua::{Function, Lua, LuaSerdeExt, RegistryKey, UserData, UserDataMethods, Value, Variadic}; use mlua::{Function, Lua, LuaSerdeExt, RegistryKey, UserData, UserDataMethods, Value, Variadic};
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use xserial_core::protocol::DecodedData; use pipeview_core::protocol::DecodedData;
use crate::config::SessionConfig; use crate::config::SessionConfig;
use crate::lua::LuaRuntime; use crate::lua::LuaRuntime;

View File

@@ -11,8 +11,8 @@ use tokio::sync::{Mutex, broadcast, mpsc};
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use tracing::{debug, error, info, warn}; use tracing::{debug, error, info, warn};
use xserial_core::pipeline::{MultiPipeline, Pipeline}; use pipeview_core::pipeline::{MultiPipeline, Pipeline};
use xserial_core::transport::Connection; use pipeview_core::transport::Connection;
use crate::cmd::SessionCmd; use crate::cmd::SessionCmd;
use crate::config::SessionConfig; use crate::config::SessionConfig;
@@ -499,7 +499,7 @@ async fn try_read(
} }
} }
fn to_io_error(err: xserial_core::error::Error) -> std::io::Error { fn to_io_error(err: pipeview_core::error::Error) -> std::io::Error {
io::Error::other(err.to_string()) io::Error::other(err.to_string())
} }
@@ -510,7 +510,7 @@ mod tests {
fn tcp_config() -> SessionConfig { fn tcp_config() -> SessionConfig {
SessionConfig { SessionConfig {
transport: xserial_core::transport::TransportConfig::Tcp { transport: pipeview_core::transport::TransportConfig::Tcp {
addr: "127.0.0.1:1".into(), addr: "127.0.0.1:1".into(),
}, },
pipelines: vec![PipelineConfig { pipelines: vec![PipelineConfig {
@@ -520,7 +520,7 @@ mod tests {
max_line_len: 65536, max_line_len: 65536,
}, },
decoder: DecoderConfig::Text { decoder: DecoderConfig::Text {
encoding: xserial_core::protocol::text::TextEncoding::Utf8, encoding: pipeview_core::protocol::text::TextEncoding::Utf8,
}, },
}], }],
..Default::default() ..Default::default()

View File

@@ -11,7 +11,7 @@ static INIT: Once = Once::new();
fn init_tracing() { fn init_tracing() {
INIT.call_once(|| { INIT.call_once(|| {
tracing_subscriber::fmt() tracing_subscriber::fmt()
.with_env_filter("xserial=trace") .with_env_filter("pipeview=trace")
.try_init() .try_init()
.ok(); .ok();
}); });
@@ -22,7 +22,7 @@ fn write_temp_lua(name: &str, script: &str) -> PathBuf {
.duration_since(std::time::UNIX_EPOCH) .duration_since(std::time::UNIX_EPOCH)
.unwrap() .unwrap()
.as_nanos(); .as_nanos();
let path = std::env::temp_dir().join(format!("xserial_{name}_{nonce}.lua")); let path = std::env::temp_dir().join(format!("pipeview_{name}_{nonce}.lua"));
fs::write(&path, script).unwrap(); fs::write(&path, script).unwrap();
path path
} }
@@ -47,18 +47,18 @@ fn hex_pipeline_lua() -> &'static str {
"# "#
} }
// ── xserial.sleep / xserial.log ────────────────────────────────── // ── pipeview.sleep / pipeview.log ──────────────────────────────────
#[tokio::test] #[tokio::test]
async fn lua_sleep_and_log() { async fn lua_sleep_and_log() {
let lua = Lua::new(); let lua = Lua::new();
xserial_client::lua::register(&lua).unwrap(); pipeview_client::lua::register(&lua).unwrap();
lua.load( lua.load(
r#" r#"
xserial.log("test start") pipeview.log("test start")
xserial.sleep(50) pipeview.sleep(50)
xserial.log("test end") pipeview.log("test end")
"#, "#,
) )
.exec_async() .exec_async()
@@ -66,15 +66,15 @@ async fn lua_sleep_and_log() {
.unwrap(); .unwrap();
} }
// ── xserial.list_ports ─────────────────────────────────────────── // ── pipeview.list_ports ───────────────────────────────────────────
#[tokio::test] #[tokio::test]
async fn lua_list_ports() { async fn lua_list_ports() {
let lua = Lua::new(); let lua = Lua::new();
xserial_client::lua::register(&lua).unwrap(); pipeview_client::lua::register(&lua).unwrap();
let result: Vec<String> = lua let result: Vec<String> = lua
.load(r#"return xserial.list_ports()"#) .load(r#"return pipeview.list_ports()"#)
.eval_async() .eval_async()
.await .await
.unwrap(); .unwrap();
@@ -84,7 +84,7 @@ async fn lua_list_ports() {
let _ = result; let _ = result;
} }
// ── xserial.open + session:send / session:read / session:close ──── // ── pipeview.open + session:send / session:read / session:close ────
#[tokio::test] #[tokio::test]
async fn lua_session_open_send_read_close() { async fn lua_session_open_send_read_close() {
@@ -102,11 +102,11 @@ async fn lua_session_open_send_read_close() {
}); });
let lua = Lua::new(); let lua = Lua::new();
xserial_client::lua::register(&lua).unwrap(); pipeview_client::lua::register(&lua).unwrap();
let script = format!( let script = format!(
r#" r#"
local sess = xserial.open({{ local sess = pipeview.open({{
transport = {{ Tcp = {{ addr = "{}" }} }}, transport = {{ Tcp = {{ addr = "{}" }} }},
pipelines = {{{}}} pipelines = {{{}}}
}}) }})
@@ -141,11 +141,11 @@ async fn lua_session_read_timeout() {
}); });
let lua = Lua::new(); let lua = Lua::new();
xserial_client::lua::register(&lua).unwrap(); pipeview_client::lua::register(&lua).unwrap();
let script = format!( let script = format!(
r#" r#"
local sess = xserial.open({{ local sess = pipeview.open({{
transport = {{ Tcp = {{ addr = "{}" }} }}, transport = {{ Tcp = {{ addr = "{}" }} }},
pipelines = {{{}}} pipelines = {{{}}}
}}) }})
@@ -162,7 +162,7 @@ async fn lua_session_read_timeout() {
lua.load(&script).exec_async().await.unwrap(); lua.load(&script).exec_async().await.unwrap();
} }
// ── xserial.open with hex decoder ──────────────────────────────── // ── pipeview.open with hex decoder ────────────────────────────────
#[tokio::test] #[tokio::test]
async fn lua_session_hex_decoder() { async fn lua_session_hex_decoder() {
@@ -176,11 +176,11 @@ async fn lua_session_hex_decoder() {
}); });
let lua = Lua::new(); let lua = Lua::new();
xserial_client::lua::register(&lua).unwrap(); pipeview_client::lua::register(&lua).unwrap();
let script = format!( let script = format!(
r#" r#"
local sess = xserial.open({{ local sess = pipeview.open({{
transport = {{ Tcp = {{ addr = "{}" }} }}, transport = {{ Tcp = {{ addr = "{}" }} }},
pipelines = {{{}}} pipelines = {{{}}}
}}) }})
@@ -201,7 +201,7 @@ async fn lua_session_hex_decoder() {
server.await.unwrap(); server.await.unwrap();
} }
// ── xserial.open with Lua framer + Lua decoder ─────────────────── // ── pipeview.open with Lua framer + Lua decoder ───────────────────
#[tokio::test] #[tokio::test]
async fn lua_session_custom_lua_pipeline() { async fn lua_session_custom_lua_pipeline() {
@@ -259,11 +259,11 @@ async fn lua_session_custom_lua_pipeline() {
}); });
let lua = Lua::new(); let lua = Lua::new();
xserial_client::lua::register(&lua).unwrap(); pipeview_client::lua::register(&lua).unwrap();
let script = format!( let script = format!(
r#" r#"
local sess = xserial.open({{ local sess = pipeview.open({{
transport = {{ Tcp = {{ addr = "{}" }} }}, transport = {{ Tcp = {{ addr = "{}" }} }},
pipelines = {{ pipelines = {{
{{ {{
@@ -311,12 +311,12 @@ async fn lua_session_on_data_callback() {
}); });
let lua = Lua::new(); let lua = Lua::new();
xserial_client::lua::register(&lua).unwrap(); pipeview_client::lua::register(&lua).unwrap();
let script = format!( let script = format!(
r#" r#"
local received = {{}} local received = {{}}
local sess = xserial.open({{ local sess = pipeview.open({{
transport = {{ Tcp = {{ addr = "{}" }} }}, transport = {{ Tcp = {{ addr = "{}" }} }},
pipelines = {{{}}} pipelines = {{{}}}
}}) }})
@@ -327,8 +327,8 @@ async fn lua_session_on_data_callback() {
for _ = 1, 50 do for _ = 1, 50 do
if #received < 2 then if #received < 2 then
xserial.poll(1) pipeview.poll(1)
xserial.sleep(10) pipeview.sleep(10)
end end
end end
@@ -371,11 +371,11 @@ async fn lua_session_reconfigure() {
}); });
let lua = Lua::new(); let lua = Lua::new();
xserial_client::lua::register(&lua).unwrap(); pipeview_client::lua::register(&lua).unwrap();
let script = format!( let script = format!(
r#" r#"
local sess = xserial.open({{ local sess = pipeview.open({{
transport = {{ Tcp = {{ addr = "{}" }} }}, transport = {{ Tcp = {{ addr = "{}" }} }},
pipelines = {{{}}} pipelines = {{{}}}
}}) }})
@@ -420,11 +420,11 @@ async fn lua_session_next_event_stream() {
}); });
let lua = Lua::new(); let lua = Lua::new();
xserial_client::lua::register(&lua).unwrap(); pipeview_client::lua::register(&lua).unwrap();
let script = format!( let script = format!(
r#" r#"
local sess = xserial.open({{ local sess = pipeview.open({{
transport = {{ Tcp = {{ addr = "{}" }} }}, transport = {{ Tcp = {{ addr = "{}" }} }},
pipelines = {{{}}} pipelines = {{{}}}
}}) }})
@@ -450,7 +450,7 @@ async fn lua_session_next_event_stream() {
server.await.unwrap(); server.await.unwrap();
} }
// ── session:off + xserial.poll ─────────────────────────────────── // ── session:off + pipeview.poll ───────────────────────────────────
#[tokio::test] #[tokio::test]
async fn lua_session_off_stops_future_callbacks() { async fn lua_session_off_stops_future_callbacks() {
@@ -466,12 +466,12 @@ async fn lua_session_off_stops_future_callbacks() {
}); });
let lua = Lua::new(); let lua = Lua::new();
xserial_client::lua::register(&lua).unwrap(); pipeview_client::lua::register(&lua).unwrap();
let script = format!( let script = format!(
r#" r#"
local received = {{}} local received = {{}}
local sess = xserial.open({{ local sess = pipeview.open({{
transport = {{ Tcp = {{ addr = "{}" }} }}, transport = {{ Tcp = {{ addr = "{}" }} }},
pipelines = {{{}}} pipelines = {{{}}}
}}) }})
@@ -482,8 +482,8 @@ async fn lua_session_off_stops_future_callbacks() {
for _ = 1, 50 do for _ = 1, 50 do
if #received == 0 then if #received == 0 then
xserial.poll(1) pipeview.poll(1)
xserial.sleep(10) pipeview.sleep(10)
end end
end end
@@ -491,8 +491,8 @@ async fn lua_session_off_stops_future_callbacks() {
assert(received[1] == "text:first") assert(received[1] == "text:first")
assert(sess:off(token) == true) assert(sess:off(token) == true)
xserial.sleep(250) pipeview.sleep(250)
xserial.poll(10) pipeview.poll(10)
assert(#received == 1, "callback should not fire after off") assert(#received == 1, "callback should not fire after off")
assert(sess:off(token) == false) assert(sess:off(token) == false)

View File

@@ -3,11 +3,11 @@ use std::time::Duration;
use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpListener; use tokio::net::TcpListener;
use xserial_client::SessionManager; use pipeview_client::SessionManager;
use xserial_client::config::{DecoderConfig, FramerConfig, PipelineConfig, SessionConfig}; use pipeview_client::config::{DecoderConfig, FramerConfig, PipelineConfig, SessionConfig};
use xserial_client::session::{Session, SessionEvent}; use pipeview_client::session::{Session, SessionEvent};
use xserial_core::protocol::DecodedData; use pipeview_core::protocol::DecodedData;
use xserial_core::transport::TransportConfig; use pipeview_core::transport::TransportConfig;
fn tcp_config(addr: String) -> SessionConfig { fn tcp_config(addr: String) -> SessionConfig {
SessionConfig { SessionConfig {
@@ -19,7 +19,7 @@ fn tcp_config(addr: String) -> SessionConfig {
max_line_len: 1024 * 1024, max_line_len: 1024 * 1024,
}, },
decoder: DecoderConfig::Text { decoder: DecoderConfig::Text {
encoding: xserial_core::protocol::text::TextEncoding::Utf8, encoding: pipeview_core::protocol::text::TextEncoding::Utf8,
}, },
}], }],
history_limit: 100, history_limit: 100,
@@ -113,7 +113,7 @@ async fn session_multi_pipeline_text_and_hex() {
uppercase: false, uppercase: false,
separator: " ".into(), separator: " ".into(),
bytes_per_group: 1, bytes_per_group: 1,
endian: xserial_core::protocol::Endian::Big, endian: pipeview_core::protocol::Endian::Big,
}, },
}); });
@@ -285,7 +285,7 @@ async fn session_reconfigure_changes_pipeline() {
uppercase: true, uppercase: true,
separator: " ".into(), separator: " ".into(),
bytes_per_group: 1, bytes_per_group: 1,
endian: xserial_core::protocol::Endian::Big, endian: pipeview_core::protocol::Endian::Big,
}; };
handle.reconfigure(new_cfg).await.unwrap(); handle.reconfigure(new_cfg).await.unwrap();

View File

@@ -1,5 +1,5 @@
[package] [package]
name = "xserial-core" name = "pipeview-core"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2024"

View File

@@ -61,11 +61,11 @@ pub struct PipelineResult {
/// Manages multiple [`Pipeline`]s, feeding the same byte stream to all of them. /// Manages multiple [`Pipeline`]s, feeding the same byte stream to all of them.
/// ///
/// ``` /// ```
/// use xserial_core::pipeline::{MultiPipeline, Pipeline}; /// use pipeview_core::pipeline::{MultiPipeline, Pipeline};
/// use xserial_core::frame::line::{LineFramer, LineConfig}; /// use pipeview_core::frame::line::{LineFramer, LineConfig};
/// use xserial_core::frame::fixed::FixedLengthFramer; /// use pipeview_core::frame::fixed::FixedLengthFramer;
/// use xserial_core::protocol::text::{TextDecoder, TextEncoding}; /// use pipeview_core::protocol::text::{TextDecoder, TextEncoding};
/// use xserial_core::protocol::hex::{HexDecoder, HexConfig}; /// use pipeview_core::protocol::hex::{HexDecoder, HexConfig};
/// ///
/// let mut mp = MultiPipeline::new(); /// let mut mp = MultiPipeline::new();
/// mp.add( /// mp.add(

View File

@@ -4,7 +4,7 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, UdpSocket}; use tokio::net::{TcpListener, UdpSocket};
use tokio::time::timeout; use tokio::time::timeout;
use xserial_core::frame::{ use pipeview_core::frame::{
Endian, Framer, Endian, Framer,
cobs::CobsFramer, cobs::CobsFramer,
cobs::cobs_encode as raw_cobs_encode, cobs::cobs_encode as raw_cobs_encode,
@@ -13,17 +13,17 @@ use xserial_core::frame::{
line::{LineConfig, LineFramer}, line::{LineConfig, LineFramer},
mixed::{MixedTextPlotConfig as MixedFramerConfig, MixedTextPlotFramer}, mixed::{MixedTextPlotConfig as MixedFramerConfig, MixedTextPlotFramer},
}; };
use xserial_core::protocol::{ use pipeview_core::protocol::{
DecodedData, ProtocolDecoder, DecodedData, ProtocolDecoder,
hex::{HexConfig, HexDecoder}, hex::{HexConfig, HexDecoder},
mixed::{MIXED_PLOT_ESCAPE, MIXED_PLOT_MARKER, MixedTextPlotConfig, MixedTextPlotDecoder}, mixed::{MIXED_PLOT_ESCAPE, MIXED_PLOT_MARKER, MixedTextPlotConfig, MixedTextPlotDecoder},
plot::{PlotConfig, PlotDecoder, PlotFormat, SampleType}, plot::{PlotConfig, PlotDecoder, PlotFormat, SampleType},
text::{TextDecoder, TextEncoding}, text::{TextDecoder, TextEncoding},
}; };
use xserial_core::transport::serial::{ use pipeview_core::transport::serial::{
SerialDataBits, SerialFlowControl, SerialParity, SerialStopBits, SerialDataBits, SerialFlowControl, SerialParity, SerialStopBits,
}; };
use xserial_core::transport::{Connection, TransportConfig, TransportType}; use pipeview_core::transport::{Connection, TransportConfig, TransportType};
const TEST_TIMEOUT: Duration = Duration::from_secs(5); const TEST_TIMEOUT: Duration = Duration::from_secs(5);

View File

@@ -1,15 +1,15 @@
[package] [package]
name = "xserial-gui" name = "pipeview-gui"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2024"
[[bin]] [[bin]]
name = "xserial-gui" name = "pipeview-gui"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
xserial-core = { path = "../xserial-core" } pipeview-core = { path = "../pipeview-core" }
xserial-client = { path = "../xserial-client" } pipeview-client = { path = "../pipeview-client" }
tokio = { workspace = true } tokio = { workspace = true }
egui = { workspace = true } egui = { workspace = true }
eframe = { workspace = true } eframe = { workspace = true }

View File

@@ -10,11 +10,11 @@ use crate::perf::{DrainStats, GuiProfiler, GuiSnapshot};
use crate::shortcuts::{self, default_bindings}; use crate::shortcuts::{self, default_bindings};
use crate::ui_fonts::{self, FontCandidate, FontChoice, UiFontSettings}; use crate::ui_fonts::{self, FontCandidate, FontChoice, UiFontSettings};
use egui::{Color32, Layout, Panel, Pos2, Rect, TextEdit, UiBuilder}; use egui::{Color32, Layout, Panel, Pos2, Rect, TextEdit, UiBuilder};
use xserial_client::SessionManager; use pipeview_client::SessionManager;
use xserial_client::config::SessionConfig; use pipeview_client::config::SessionConfig;
use xserial_client::session::SessionEvent; use pipeview_client::session::SessionEvent;
use xserial_core::protocol::DecodedData; use pipeview_core::protocol::DecodedData;
use xserial_core::transport::TransportConfig; use pipeview_core::transport::TransportConfig;
const DATA_REPAINT_INTERVAL: Duration = Duration::from_millis(33); const DATA_REPAINT_INTERVAL: Duration = Duration::from_millis(33);
@@ -851,7 +851,7 @@ impl XserialApp {
fn render_top_bar(&mut self, ui: &mut egui::Ui) { fn render_top_bar(&mut self, ui: &mut egui::Ui) {
Panel::top("top_bar").show_inside(ui, |ui| { Panel::top("top_bar").show_inside(ui, |ui| {
ui.horizontal_wrapped(|ui| { ui.horizontal_wrapped(|ui| {
ui.heading("xserial"); ui.heading("pipeview");
ui.separator(); ui.separator();
// ui.label(format!( // ui.label(format!(
// "Fonts: {} + {} {:.1} pt", // "Fonts: {} + {} {:.1} pt",
@@ -1434,8 +1434,8 @@ fn build_payload(tab: &SessionTab) -> Result<Option<Vec<u8>>, String> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::transport_summary; use super::transport_summary;
use xserial_core::transport::TransportConfig; use pipeview_core::transport::TransportConfig;
use xserial_core::transport::serial::{ use pipeview_core::transport::serial::{
SerialDataBits, SerialFlowControl, SerialParity, SerialStopBits, SerialDataBits, SerialFlowControl, SerialParity, SerialStopBits,
}; };

View File

@@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tracing::warn; use tracing::warn;
use xserial_client::config::SessionConfig; use pipeview_client::config::SessionConfig;
const GUI_STATE_FILE_NAME: &str = "gui-state.json"; const GUI_STATE_FILE_NAME: &str = "gui-state.json";
@@ -54,7 +54,7 @@ fn gui_state_path() -> PathBuf {
gui_state_path_for_os_and_env(env::consts::OS, |key| env::var(key).ok()) gui_state_path_for_os_and_env(env::consts::OS, |key| env::var(key).ok())
} }
/// Returns the xserial configuration directory (the parent of gui-state.json). /// Returns the pipeview configuration directory (the parent of gui-state.json).
pub fn config_dir() -> PathBuf { pub fn config_dir() -> PathBuf {
gui_state_path() gui_state_path()
.parent() .parent()
@@ -67,12 +67,12 @@ fn gui_state_path_for_os_and_env(os: &str, get_env: impl Fn(&str) -> Option<Stri
"windows" => { "windows" => {
if let Some(path) = get_env("APPDATA").filter(|path| !path.trim().is_empty()) { if let Some(path) = get_env("APPDATA").filter(|path| !path.trim().is_empty()) {
return PathBuf::from(path) return PathBuf::from(path)
.join("xserial") .join("pipeview")
.join(GUI_STATE_FILE_NAME); .join(GUI_STATE_FILE_NAME);
} }
if let Some(path) = get_env("LOCALAPPDATA").filter(|path| !path.trim().is_empty()) { if let Some(path) = get_env("LOCALAPPDATA").filter(|path| !path.trim().is_empty()) {
return PathBuf::from(path) return PathBuf::from(path)
.join("xserial") .join("pipeview")
.join(GUI_STATE_FILE_NAME); .join(GUI_STATE_FILE_NAME);
} }
} }
@@ -81,20 +81,20 @@ fn gui_state_path_for_os_and_env(os: &str, get_env: impl Fn(&str) -> Option<Stri
return PathBuf::from(home) return PathBuf::from(home)
.join("Library") .join("Library")
.join("Application Support") .join("Application Support")
.join("xserial") .join("pipeview")
.join(GUI_STATE_FILE_NAME); .join(GUI_STATE_FILE_NAME);
} }
} }
_ => { _ => {
if let Some(path) = get_env("XDG_CONFIG_HOME").filter(|path| !path.trim().is_empty()) { if let Some(path) = get_env("XDG_CONFIG_HOME").filter(|path| !path.trim().is_empty()) {
return PathBuf::from(path) return PathBuf::from(path)
.join("xserial") .join("pipeview")
.join(GUI_STATE_FILE_NAME); .join(GUI_STATE_FILE_NAME);
} }
if let Some(home) = get_env("HOME").filter(|path| !path.trim().is_empty()) { if let Some(home) = get_env("HOME").filter(|path| !path.trim().is_empty()) {
return PathBuf::from(home) return PathBuf::from(home)
.join(".config") .join(".config")
.join("xserial") .join("pipeview")
.join(GUI_STATE_FILE_NAME); .join(GUI_STATE_FILE_NAME);
} }
} }
@@ -124,7 +124,7 @@ const fn default_true() -> bool {
mod tests { mod tests {
use super::*; use super::*;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use xserial_core::transport::TransportConfig; use pipeview_core::transport::TransportConfig;
#[test] #[test]
fn windows_gui_state_path_uses_appdata() { fn windows_gui_state_path_uses_appdata() {
@@ -135,7 +135,7 @@ mod tests {
assert_eq!( assert_eq!(
path, path,
PathBuf::from(r"C:\Users\Test\AppData\Roaming") PathBuf::from(r"C:\Users\Test\AppData\Roaming")
.join("xserial") .join("pipeview")
.join(GUI_STATE_FILE_NAME) .join(GUI_STATE_FILE_NAME)
); );
} }
@@ -146,7 +146,7 @@ mod tests {
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
.unwrap() .unwrap()
.as_nanos(); .as_nanos();
let dir = env::temp_dir().join(format!("xserial-gui-state-{unique}")); let dir = env::temp_dir().join(format!("pipeview-gui-state-{unique}"));
let path = dir.join(GUI_STATE_FILE_NAME); let path = dir.join(GUI_STATE_FILE_NAME);
let state = PersistedGuiState { let state = PersistedGuiState {
sessions: vec![SessionConfig { sessions: vec![SessionConfig {

View File

@@ -1,10 +1,10 @@
use egui_plot::PlotBounds; use egui_plot::PlotBounds;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use xserial_client::RingBuffer; use pipeview_client::RingBuffer;
use xserial_client::event::DecodedEntry; use pipeview_client::event::DecodedEntry;
use xserial_core::protocol::DecodedData; use pipeview_core::protocol::DecodedData;
use xserial_core::protocol::plot::{PlotFormat, PlotFrame}; use pipeview_core::protocol::plot::{PlotFormat, PlotFrame};
#[derive(Clone)] #[derive(Clone)]
pub enum LineDirection { pub enum LineDirection {
@@ -716,9 +716,9 @@ impl PlotBuffer {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use xserial_client::event::DecodedEntry; use pipeview_client::event::DecodedEntry;
use xserial_core::protocol::DecodedData; use pipeview_core::protocol::DecodedData;
use xserial_core::protocol::plot::{PlotFrame, SampleType}; use pipeview_core::protocol::plot::{PlotFrame, SampleType};
fn plot_entry() -> DecodedEntry { fn plot_entry() -> DecodedEntry {
DecodedEntry { DecodedEntry {

View File

@@ -6,8 +6,8 @@ use std::thread;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use xserial_client::event::DecodedEntry; use pipeview_client::event::DecodedEntry;
use xserial_core::protocol::DecodedData; use pipeview_core::protocol::DecodedData;
/// Manages background file logging via a dedicated writer thread. /// Manages background file logging via a dedicated writer thread.
/// ///
@@ -30,7 +30,7 @@ impl LogWriter {
let mut writer = BufWriter::with_capacity(1024, file); let mut writer = BufWriter::with_capacity(1024, file);
let (sender, receiver) = mpsc::channel::<String>(); let (sender, receiver) = mpsc::channel::<String>();
let thread_name = format!("xserial-log-{}", path.display()); let thread_name = format!("pipeview-log-{}", path.display());
thread::Builder::new().name(thread_name).spawn(move || { thread::Builder::new().name(thread_name).spawn(move || {
while let Ok(line) = receiver.recv() { while let Ok(line) = receiver.recv() {
if writeln!(writer, "{line}").is_err() { if writeln!(writer, "{line}").is_err() {

View File

@@ -7,7 +7,7 @@ mod perf;
mod shortcuts; mod shortcuts;
mod ui_fonts; mod ui_fonts;
use xserial_client::SessionManager; use pipeview_client::SessionManager;
fn main() { fn main() {
tracing_subscriber::fmt() tracing_subscriber::fmt()
@@ -21,7 +21,7 @@ fn main() {
let rx = mgr.subscribe(); let rx = mgr.subscribe();
let _ = eframe::run_native( let _ = eframe::run_native(
"xserial", "pipeview",
eframe::NativeOptions::default(), eframe::NativeOptions::default(),
Box::new(|cc| Ok(Box::new(app::XserialApp::new(mgr, rx, cc.egui_ctx.clone())))), Box::new(|cc| Ok(Box::new(app::XserialApp::new(mgr, rx, cc.egui_ctx.clone())))),
); );

View File

@@ -1,10 +1,10 @@
use egui::{ComboBox, DragValue, ScrollArea, TextEdit, Ui}; use egui::{ComboBox, DragValue, ScrollArea, TextEdit, Ui};
use xserial_client::config::{DecoderConfig, FramerConfig, PipelineConfig, SessionConfig}; use pipeview_client::config::{DecoderConfig, FramerConfig, PipelineConfig, SessionConfig};
use xserial_core::protocol::Endian; use pipeview_core::protocol::Endian;
use xserial_core::protocol::plot::{PlotFormat, SampleType}; use pipeview_core::protocol::plot::{PlotFormat, SampleType};
use xserial_core::protocol::text::TextEncoding; use pipeview_core::protocol::text::TextEncoding;
use xserial_core::transport::TransportConfig; use pipeview_core::transport::TransportConfig;
use xserial_core::transport::serial::{ use pipeview_core::transport::serial::{
SerialDataBits, SerialFlowControl, SerialParity, SerialStopBits, SerialTransport, SerialDataBits, SerialFlowControl, SerialParity, SerialStopBits, SerialTransport,
}; };

View File

@@ -202,7 +202,7 @@ impl GuiProfiler {
let repaints = self.repaint_counter.take(); let repaints = self.repaint_counter.take();
info!( info!(
target: "xserial_gui::perf", target: "pipeview_gui::perf",
frames = self.interval_stats.frames.count, frames = self.interval_stats.frames.count,
frame_avg_ms = self.interval_stats.frames.avg_ms(), frame_avg_ms = self.interval_stats.frames.avg_ms(),
frame_max_ms = self.interval_stats.frames.max_ms(), frame_max_ms = self.interval_stats.frames.max_ms(),

View File

@@ -358,12 +358,12 @@ fn font_settings_path_for_os_and_env(
"windows" => { "windows" => {
if let Some(path) = get_env("APPDATA").filter(|path| !path.trim().is_empty()) { if let Some(path) = get_env("APPDATA").filter(|path| !path.trim().is_empty()) {
return PathBuf::from(path) return PathBuf::from(path)
.join("xserial") .join("pipeview")
.join(FONT_SETTINGS_FILE_NAME); .join(FONT_SETTINGS_FILE_NAME);
} }
if let Some(path) = get_env("LOCALAPPDATA").filter(|path| !path.trim().is_empty()) { if let Some(path) = get_env("LOCALAPPDATA").filter(|path| !path.trim().is_empty()) {
return PathBuf::from(path) return PathBuf::from(path)
.join("xserial") .join("pipeview")
.join(FONT_SETTINGS_FILE_NAME); .join(FONT_SETTINGS_FILE_NAME);
} }
} }
@@ -372,20 +372,20 @@ fn font_settings_path_for_os_and_env(
return PathBuf::from(home) return PathBuf::from(home)
.join("Library") .join("Library")
.join("Application Support") .join("Application Support")
.join("xserial") .join("pipeview")
.join(FONT_SETTINGS_FILE_NAME); .join(FONT_SETTINGS_FILE_NAME);
} }
} }
_ => { _ => {
if let Some(path) = get_env("XDG_CONFIG_HOME").filter(|path| !path.trim().is_empty()) { if let Some(path) = get_env("XDG_CONFIG_HOME").filter(|path| !path.trim().is_empty()) {
return PathBuf::from(path) return PathBuf::from(path)
.join("xserial") .join("pipeview")
.join(FONT_SETTINGS_FILE_NAME); .join(FONT_SETTINGS_FILE_NAME);
} }
if let Some(home) = get_env("HOME").filter(|path| !path.trim().is_empty()) { if let Some(home) = get_env("HOME").filter(|path| !path.trim().is_empty()) {
return PathBuf::from(home) return PathBuf::from(home)
.join(".config") .join(".config")
.join("xserial") .join("pipeview")
.join(FONT_SETTINGS_FILE_NAME); .join(FONT_SETTINGS_FILE_NAME);
} }
} }
@@ -591,7 +591,7 @@ mod tests {
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
.unwrap() .unwrap()
.as_nanos(); .as_nanos();
let dir = env::temp_dir().join(format!("xserial-gui-font-settings-{unique}")); let dir = env::temp_dir().join(format!("pipeview-gui-font-settings-{unique}"));
let path = dir.join("gui-fonts.json"); let path = dir.join("gui-fonts.json");
let settings = UiFontSettings { let settings = UiFontSettings {
primary_choice: FontChoice::System(String::from("primary")), primary_choice: FontChoice::System(String::from("primary")),
@@ -622,7 +622,7 @@ mod tests {
assert_eq!( assert_eq!(
path, path,
PathBuf::from("/tmp/xdg-config") PathBuf::from("/tmp/xdg-config")
.join("xserial") .join("pipeview")
.join(FONT_SETTINGS_FILE_NAME) .join(FONT_SETTINGS_FILE_NAME)
); );
} }
@@ -636,7 +636,7 @@ mod tests {
assert_eq!( assert_eq!(
path, path,
PathBuf::from(r"C:\Users\Test\AppData\Roaming") PathBuf::from(r"C:\Users\Test\AppData\Roaming")
.join("xserial") .join("pipeview")
.join(FONT_SETTINGS_FILE_NAME) .join(FONT_SETTINGS_FILE_NAME)
); );
} }
@@ -652,7 +652,7 @@ mod tests {
PathBuf::from("/Users/tester") PathBuf::from("/Users/tester")
.join("Library") .join("Library")
.join("Application Support") .join("Application Support")
.join("xserial") .join("pipeview")
.join(FONT_SETTINGS_FILE_NAME) .join(FONT_SETTINGS_FILE_NAME)
); );
} }

View File

@@ -1,15 +1,15 @@
[package] [package]
name = "xserial-tui" name = "pipeview-tui"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2024"
[[bin]] [[bin]]
name = "xserial-tui" name = "pipeview-tui"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
xserial-core = { path = "../xserial-core" } pipeview-core = { path = "../pipeview-core" }
xserial-client = { path = "../xserial-client" } pipeview-client = { path = "../pipeview-client" }
tokio = { workspace = true } tokio = { workspace = true }
ratatui = { workspace = true } ratatui = { workspace = true }
crossterm = { workspace = true } crossterm = { workspace = true }

View File

@@ -3,12 +3,12 @@ use std::{io, time::Duration};
use crossterm::event::{self, Event, KeyCode, KeyEventKind, KeyModifiers}; use crossterm::event::{self, Event, KeyCode, KeyEventKind, KeyModifiers};
use ratatui::DefaultTerminal; use ratatui::DefaultTerminal;
use tokio::sync::broadcast; use tokio::sync::broadcast;
use xserial_client::{ use pipeview_client::{
DecoderConfig, FramerConfig, PipelineConfig, SessionConfig, SessionEvent, SessionId, DecoderConfig, FramerConfig, PipelineConfig, SessionConfig, SessionEvent, SessionId,
SessionManager, SessionManager,
}; };
use xserial_core::protocol::DecodedData; use pipeview_core::protocol::DecodedData;
use xserial_core::transport::{ use pipeview_core::transport::{
TransportConfig, TransportType, TransportConfig, TransportType,
serial::{SerialDataBits, SerialFlowControl, SerialParity, SerialStopBits, SerialTransport}, serial::{SerialDataBits, SerialFlowControl, SerialParity, SerialStopBits, SerialTransport},
}; };

View File

@@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tracing::warn; use tracing::warn;
use xserial_client::SessionConfig; use pipeview_client::SessionConfig;
const TUI_STATE_FILE_NAME: &str = "tui-state.json"; const TUI_STATE_FILE_NAME: &str = "tui-state.json";
@@ -49,12 +49,12 @@ fn state_path_for_os_and_env(os: &str, get_env: impl Fn(&str) -> Option<String>)
"windows" => { "windows" => {
if let Some(path) = get_env("APPDATA").filter(|path| !path.trim().is_empty()) { if let Some(path) = get_env("APPDATA").filter(|path| !path.trim().is_empty()) {
return PathBuf::from(path) return PathBuf::from(path)
.join("xserial") .join("pipeview")
.join(TUI_STATE_FILE_NAME); .join(TUI_STATE_FILE_NAME);
} }
if let Some(path) = get_env("LOCALAPPDATA").filter(|path| !path.trim().is_empty()) { if let Some(path) = get_env("LOCALAPPDATA").filter(|path| !path.trim().is_empty()) {
return PathBuf::from(path) return PathBuf::from(path)
.join("xserial") .join("pipeview")
.join(TUI_STATE_FILE_NAME); .join(TUI_STATE_FILE_NAME);
} }
} }
@@ -63,20 +63,20 @@ fn state_path_for_os_and_env(os: &str, get_env: impl Fn(&str) -> Option<String>)
return PathBuf::from(home) return PathBuf::from(home)
.join("Library") .join("Library")
.join("Application Support") .join("Application Support")
.join("xserial") .join("pipeview")
.join(TUI_STATE_FILE_NAME); .join(TUI_STATE_FILE_NAME);
} }
} }
_ => { _ => {
if let Some(path) = get_env("XDG_CONFIG_HOME").filter(|path| !path.trim().is_empty()) { if let Some(path) = get_env("XDG_CONFIG_HOME").filter(|path| !path.trim().is_empty()) {
return PathBuf::from(path) return PathBuf::from(path)
.join("xserial") .join("pipeview")
.join(TUI_STATE_FILE_NAME); .join(TUI_STATE_FILE_NAME);
} }
if let Some(home) = get_env("HOME").filter(|path| !path.trim().is_empty()) { if let Some(home) = get_env("HOME").filter(|path| !path.trim().is_empty()) {
return PathBuf::from(home) return PathBuf::from(home)
.join(".config") .join(".config")
.join("xserial") .join("pipeview")
.join(TUI_STATE_FILE_NAME); .join(TUI_STATE_FILE_NAME);
} }
} }

View File

@@ -1,7 +1,7 @@
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use xserial_client::{DecodedEntry, RingBuffer}; use pipeview_client::{DecodedEntry, RingBuffer};
use xserial_core::protocol::DecodedData; use pipeview_core::protocol::DecodedData;
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
pub enum LineDirection { pub enum LineDirection {

View File

@@ -10,7 +10,7 @@ use crossterm::{
terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode}, terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
}; };
use ratatui::{Terminal, backend::CrosstermBackend}; use ratatui::{Terminal, backend::CrosstermBackend};
use xserial_client::SessionManager; use pipeview_client::SessionManager;
#[tokio::main] #[tokio::main]
async fn main() -> io::Result<()> { async fn main() -> io::Result<()> {

View File

@@ -100,7 +100,7 @@ fn render_main(frame: &mut Frame, app: &App, area: Rect) {
app.help_text(), app.help_text(),
app.notice().unwrap_or("") app.notice().unwrap_or("")
)) ))
.block(Block::default().borders(Borders::ALL).title("xserial-tui")) .block(Block::default().borders(Borders::ALL).title("pipeview-tui"))
.wrap(Wrap { trim: false }), .wrap(Wrap { trim: false }),
area, area,
); );

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Generate fake drone telemetry data for testing xserial Lua decoder.""" """Generate fake drone telemetry data for testing pipeview Lua decoder."""
import argparse import argparse
import math import math

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""TCP server that sends plot waveform frames or text lines for xserial GUI.""" """TCP server that sends plot waveform frames or text lines for pipeview GUI."""
import argparse import argparse
import math import math
@@ -116,7 +116,7 @@ def is_disconnect_error(err: OSError) -> bool:
def main() -> None: def main() -> None:
parser = argparse.ArgumentParser(description="xserial plot test server") parser = argparse.ArgumentParser(description="pipeview plot test server")
parser.add_argument("--host", default="127.0.0.1") parser.add_argument("--host", default="127.0.0.1")
parser.add_argument("--port", type=int, default=8080) parser.add_argument("--port", type=int, default=8080)
parser.add_argument("--channels", type=int, default=1) parser.add_argument("--channels", type=int, default=1)

View File

@@ -429,7 +429,7 @@ int main(int argc, char **argv) {
double frame_interval = (double)args.samples_per_channel / args.rate; double frame_interval = (double)args.samples_per_channel / args.rate;
double frame_rate = args.rate / (double)args.samples_per_channel; double frame_rate = args.rate / (double)args.samples_per_channel;
printf("═══ xserial Serial Plot Generator ═══\n"); printf("═══ pipeview Serial Plot Generator ═══\n");
printf("串口: %s @ %d baud\n", args.port, args.baudrate); printf("串口: %s @ %d baud\n", args.port, args.baudrate);
printf("通道: %u 格式: %s\n", args.channels, format_name); printf("通道: %u 格式: %s\n", args.channels, format_name);
printf("频率: %.1f Hz 振幅: %.1f\n", args.freq, args.amp); printf("频率: %.1f Hz 振幅: %.1f\n", args.freq, args.amp);

View File

@@ -208,7 +208,7 @@ int main(int argc, char **argv) {
double interval = 1.0 / args.rate; double interval = 1.0 / args.rate;
printf("═══ xserial Plain Text Generator ═══\n"); printf("═══ pipeview Plain Text Generator ═══\n");
printf("串口: %s @ %d baud\n", args.port, args.baudrate); printf("串口: %s @ %d baud\n", args.port, args.baudrate);
printf("通道: %u 振幅: %.1f 频率: %.1f Hz\n", args.channels, args.amp, args.freq); printf("通道: %u 振幅: %.1f 频率: %.1f Hz\n", args.channels, args.amp, args.freq);
printf("速率: %.0f lines/sec (间隔 %.3f ms)\n", args.rate, interval * 1000.0); printf("速率: %.0f lines/sec (间隔 %.3f ms)\n", args.rate, interval * 1000.0);