Files
xserial/README.md

13 KiB
Raw Blame History

pipeview

跨平台串口 / TCP / UDP 数据观测工具 — 可配置分帧、协议解码、多会话管理、实时波形绘图,单二进制零依赖。

基于 Rust + egui 构建,支持 Lua 脚本扩展。

English


目录


功能特性

传输层

类型 说明 配置项
Serial 串口通信 端口名、波特率 (30012M)、数据位 (5/6/7/8)、校验位 (None/Odd/Even)、停止位 (1/2)、流控 (None/Software/Hardware)、DTR/RTS 控制
TCP TCP 客户端 目标地址 host:port
UDP UDP 通信 绑定地址 host:port,可选远端地址

分帧器Framer

将原始字节流切分为独立帧。每个 Session 可配置多条独立管线,同一字节流并行送入多个 framer→decoder 链路。

分帧器 说明 配置参数
Line \n 分割文本行 strip_cr(去除 \r)、max_line_len(最大行长度)
Fixed 固定字节数为一帧 frame_len(帧长度)
Length 长度前缀协议 len_bytes (1/2/4/8)、endian (大小端)、length_includes_selfmax_payload
COBS Consistent Overhead Byte Stuffing 编码 max_frame(最大帧长)
MixedTextPlot 单连接混合文本行 + COBS 编码的 plot 帧 strip_crmax_line_lenmax_plot_frame
Lua 用户自定义分帧脚本 script_pathLua 脚本路径)

解码器Decoder

将帧数据解析为可展示的内容。

解码器 输出类型 配置参数
Text 文本 encodingUTF-8 / Latin1 / ASCII
Hex 十六进制 uppercaseseparatorbytes_per_groupendian
Plot 波形数据 sample_type (i8f64)、endianchannels (164)、format (Interleaved / Block / XY)
MixedTextPlot 混合文本 + 波形 encoding
Lua 自定义 script_pathLua 脚本路径)

Plot 采样格式:

格式 说明 字节排列
Interleaved 多通道交叉排列 [ch0_s0, ch1_s0, ch2_s0, ch0_s1, ch1_s1, …]
Block 按通道分块排列 [ch0_s0, ch0_s1, …, ch1_s0, ch1_s1, …]
XY 2 通道交替 x/y [x0, y0, x1, y1, …]

支持的采样类型:i8u8i16u16i32u32i64u64f32f64

视图

  • 文本视图 — 带时间戳、方向标记 ([IN]/[OUT])、管线标签的格式化文本流。支持搜索(Ctrl+F)、大小写匹配、匹配计数和高亮。
  • 十六进制视图 — hex dump 与 ASCII 侧栏并排展示,可按分组和大小端解析多字节数值。
  • 波形视图 — 基于 egui_plot 的实时波形。支持自动缩放、框选缩放、坐标轴锁定、跟随最新数据、浮动窗口、通道图例。

会话管理

  • 多会话并发 — 标签页切换,每个 Session 独立配置
  • 连接控制 — Connect / Disconnect / Reconnect支持断线自动重连
  • 运行时重配置 — 修改分帧器/解码器参数无需断开连接
  • 数据发送 — Text 模式UTF-8可选换行符和 Hex 模式(十六进制字节)。支持 None / LF / CR / CRLF 四种行尾
  • 环形缓冲 — 默认 10,000 条历史记录,可配置 1001,000,000
  • 日志到文件 — 每行数据实时写入1KB 缓冲 + 后台线程,不阻塞 UI
  • 搜索Ctrl+F 呼出搜索栏大小写敏感切换F3/Shift+F3 前后跳转

Lua 脚本扩展

内置 LuaJIT 运行时:

  • 自定义分帧器 — 实现 feed(bytes)flush()reset()pending_len() 四个函数
  • 自定义解码器 — 实现 decode(frame) 函数,返回 text/hex/plot/binary 四种类型
  • 会话 APIpipeview.open() 创建 Session、session:on_data() 事件回调、session:send() 发送数据
  • 工具函数pipeview.list_ports()pipeview.sleep(ms)pipeview.poll(limit)pipeview.log(msg)

快捷键

快捷键 操作
Ctrl+N 新建会话
Ctrl+E 编辑当前会话
Ctrl+W 删除当前会话
Ctrl+F5 切换连接
Ctrl+T / Ctrl+H / Ctrl+P 切换到文本 / 十六进制 / 波形视图
Ctrl+Tab / Ctrl+Shift+Tab 下一个 / 上一个标签页
Ctrl+L 清空输出
Ctrl+F 搜索
F3 / Shift+F3 上一个 / 下一个匹配
Ctrl+, UI 设置
Esc 关闭浮层

快速开始

前置条件

平台 依赖
Linux libudev-devapt install libudev-dev
macOS 无需额外依赖
Windows 无需额外依赖
所有平台 Rust ≥ 1.85、C 编译器GCC / Clang / MSVC

构建与运行

# 克隆项目
git clone https://github.com/your-org/pipeview.git
cd pipeview

# 编译运行
cargo run -p pipeview-gui

# 运行测试
cargo test --workspace           # ~308 个测试
cargo clippy --workspace --all-targets -- -D warnings

发布构建

cargo build -p pipeview-gui --release
# 二进制位于 target/release/pipeview-gui (Linux/macOS)
# 或 target/release/pipeview-gui.exe (Windows)

完整示例:无人机遥测解析

以 Betaflight/INAV 飞控遥测为例,数据格式为:

AHRS q:1.0000,0.0998,0.0499,0.0200|YPR:8.87,4.44,2.96|Gyro:14.78,8.87,5.92|RC:1559,1544,1500,1519|M:1612,1588,1603,1597|L:0 F:1 C:0

步骤 1启动测试数据源

python tools/test_drone.py --rate 10 --port 8091

输出:

Listening on 127.0.0.1:8091, waiting for connections...

步骤 2配置 Session

在 pipeview-gui 中创建 Session

配置项
Transport TCP 127.0.0.1:8091
Pipeline 1 Framer: Line → Decoder: Lua → 选择 examples/drone_text.lua
Pipeline 2 Framer: Line → Decoder: Lua → 选择 examples/drone_plot.lua

步骤 3查看结果

  • 文本视图 — 显示格式化的传感器数据
  • 波形视图 — 显示 Gyro 三轴实时曲线 (gz/gy/gx)

examples/drone_plot.lua 的核心逻辑:

return {
    decode = function(frame)
        local gz, gy, gx = frame:match("Gyro:([%d%.%-]+),([%d%.%-]+),([%d%.%-]+)")
        return {
            kind = "plot",
            channels = { { tonumber(gz) }, { tonumber(gy) }, { tonumber(gx) } },
            sample_type = "F64",
            format = "Block",
        }
    end,
}

Lua 脚本开发指南

分帧器 API

分帧器将原始字节流切分为帧Lua 脚本必须返回包含以下函数的 table

return {
    -- 输入新到达的字节返回帧数组Lua strings
    feed = function(bytes)
        -- bytes: Lua string原始字节
        -- 返回: { frame1, frame2, ... } 或 nil
    end,

    -- 刷新缓冲区中残留的数据
    flush = function()
        -- 返回: 最后一帧Lua string或 nil
    end,

    -- 重置内部状态
    reset = function()
    end,

    -- 返回缓冲区中待处理的字节数
    pending_len = function()
        -- 返回: number
    end,
}

参考实现:tests/lua_line_framer.lua(按 \n 分割的行分帧器)

解码器 API

解码器将帧解析为结构化数据Lua 脚本必须返回包含 decode 函数的 table

return {
    decode = function(frame)
        -- frame: Lua string来自分帧器的一帧
        -- 返回 nil → 跳过此帧
        -- 返回 string → 自动视为 Text
        -- 返回 table → 必须包含 kind 字段
    end,
}

返回值格式:

kind 必需字段 可选字段 用途
"text" data: string 文本视图
"hex" data: string 十六进制视图
"binary" data: string 原始二进制
"plot" channels: {{number,…},…} sample_typeformat 波形视图

Plot 返回值示例:

return {
    kind = "plot",
    channels = {
        { 1.0, 2.0, 3.0 },  -- channel 0
        { 4.0, 5.0, 6.0 },  -- channel 1
    },
    sample_type = "F64",     -- 默认 F64可选 I8/U8/I16/U16/I32/U32/I64/U64/F32
    format = "Block",        -- 默认 Interleaved可选 Block/XY
}

更多示例见 examples/ 目录。


架构

┌──────────────────────────────────────────────────┐
│  pipeview-gui (egui)       pipeview-tui (ratatui) │
├──────────────────────────────────────────────────┤
│  pipeview-client                                  │
│  SessionManager · Session · Config · History     │
│  Lua Runtime (mlua / LuaJIT)                     │
├──────────────────────────────────────────────────┤
│  pipeview-core                                    │
│  Transport ──▶ Frame ──▶ Protocol ──▶ Pipeline  │
└──────────────────────────────────────────────────┘
Crate 类型 职责
pipeview-core library 传输层Serial/TCP/UDP、分帧器Line/Fixed/Length/COBS/Mixed/Lua、协议解码器Text/Hex/Plot、MultiPipeline
pipeview-client library Session 生命周期管理、SessionManager、事件广播tokio broadcast、RingBuffer 历史、Lua 运行时及会话 API
pipeview-gui binary egui 桌面应用,包含 sidebar/config/console/text/hex/plot 面板、键盘快捷键、字体管理、性能分析
pipeview-tui binary ratatui 终端应用(功能未对齐 GUI仍在开发中

依赖方向: core ← client ← {gui, tui}

数据流:

[Transport] → read bytes → [MultiPipeline]
    → Pipeline 1: Framer → Decoder → DecodedEntry → broadcast → GUI buffers
    → Pipeline 2: Framer → Decoder → DecodedEntry → broadcast → GUI buffers
    → ...

每条管线独立分帧、解码,互不干扰。只有成功解码的管线产生输出。


配置与持久化

GUI 状态自动保存,路径遵循各平台规范:

平台 路径
Linux $XDG_CONFIG_HOME/pipeview/gui-state.json~/.config/pipeview/gui-state.json
macOS ~/Library/Application Support/pipeview/gui-state.json
Windows %APPDATA%\pipeview\gui-state.json

持久化的内容包括Session 配置(传输参数、管线设置)、日志开关及路径、活动标签页、显示选项。

日志文件默认保存在配置目录的 logs/ 子目录下,文件命名格式为 session_{id}_{timestamp}.log


开发工具

测试数据生成器

# Plot 波形测试数据
python tools/test_plot.py --wire-format mixed --host 127.0.0.1 --port 8091
python tools/test_plot.py --wire-format mixed --format xy --channels 2
python tools/test_plot.py --wire-format raw --channels 2 --framelen 256

# 无人机遥测测试数据
python tools/test_drone.py --rate 10 --port 8092

性能分析

RUST_LOG=pipeview_gui::perf=info XSERIAL_GUI_PROFILE=1 cargo run -p pipeview-gui
XSERIAL_GUI_PROFILE_INTERVAL_MS=500 cargo run -p pipeview-gui

输出每帧的耗时、事件 drain 耗时、text/hex/plot 渲染耗时、plot 点数统计。

日志

RUST_LOG=info cargo run -p pipeview-gui          # 应用日志
RUST_LOG=pipeview_gui=debug cargo run -p pipeview-gui  # 详细日志

使用 tracing-subscriber + RUST_LOG 环境变量控制。

项目结构

crates/
  pipeview-core/        # 传输、分帧、协议
  pipeview-client/      # 会话管理、Lua 运行时
  pipeview-gui/         # egui 桌面应用
  pipeview-tui/         # ratatui 终端应用
examples/              # Lua 脚本示例
  drone_plot.lua       # 飞控遥测波形解码器
  drone_text.lua       # 飞控遥测文本解码器
tests/                 # Lua 测试 fixture
tools/                 # 开发辅助工具
  test_plot.py         # 波形测试数据生成器
  test_drone.py        # 飞控测试数据生成器
  test_plot_serial.c   # C 串口波形测试客户端
  test_text_serial.c   # C 串口文本测试客户端
  xs_mixed_plot.h      # MixedTextPlot 协议参考头文件

技术栈

  • 运行时tokio (multi-thread)
  • 串口tokio-serial + serialport
  • GUIegui + egui_plot
  • Luamlua 0.11, LuaJIT (vendored 编译), async/serde/send
  • 事件分发tokio::sync::broadcast(多订阅者)
  • 零 feature flags、零 build script、零条件编译

License

MIT