Skip to main content

Module diagnostics

Module diagnostics 

Source
Expand description

高级诊断接口(逃生舱)

本模块提供对底层 driver 的受限访问,用于高级诊断、调试和性能分析场景。

§设计理念

这是一个受限的逃生舱(Escape Hatch),暴露了底层 driver 的部分功能:

  • ✅ 可以访问 context.hooks(注册自定义回调)
  • ✅ 可以访问 send_frame(发送原始 CAN 帧)
  • ❌ 不能直接调用 enable/disable(保持状态机安全)

§线程安全

PiperDiagnostics 持有 Arc<piper_driver::Piper>,可以安全地跨线程传递:

  • 独立生命周期:不受原始 Piper 实例生命周期约束
  • 跨线程使用:可以在诊断线程中长期持有
  • 'static:可以存储在 static 变量或线程局部存储中

§权衡说明

由于持有 Arc 而非引用,PiperDiagnostics 脱离了 TypeState 的直接保护。 这是逃生舱设计的有意权衡

  • 优点:灵活性极高,适合复杂的诊断场景
  • 缺点:无法在编译时保证关联的 Piper 仍然处于特定状态
  • 缓解:通过运行时检查和文档警告来保证安全

§使用场景

  • 自定义诊断工具
  • 高级抓包和调试
  • 性能分析和优化
  • 非标准回放逻辑
  • 后台监控线程

§安全注意事项

此接口提供的底层能力可能破坏状态机的不变性。 使用时需注意:

  1. 不要在 Active 状态下发送控制指令(会导致双控制流冲突)
  2. 不要手动调用 disable()(应该通过 PiperDrop 来处理)
  3. 确保回调执行时间 <1μs(否则会影响实时性能)
  4. 注意生命周期:即使持有 Arc,也要确保关联的 Piper 实例未被销毁

§示例

§基础使用

use piper_client::{PiperBuilder};
use piper_driver::recording::AsyncRecordingHook;
use std::sync::Arc;

let robot = PiperBuilder::new()
    .interface("can0")
    .build()?;

let active = robot.enable_position_mode(Default::default())?;

// 获取诊断接口(持有 Arc,独立生命周期)
let diag = active.diagnostics();

// 创建自定义录制钩子
let (hook, rx) = AsyncRecordingHook::new();

// 注册钩子
diag.register_callback(Arc::new(hook))?;

// 在后台线程处理录制数据
std::thread::spawn(move || {
    while let Ok(frame) = rx.recv() {
        println!("Received CAN frame: 0x{:03X}", frame.id);
    }
});

§跨线程长期持有

use piper_client::{PiperBuilder};
use std::thread;

let robot = PiperBuilder::new()
    .interface("can0")
    .build()?;

let active = robot.enable_position_mode(Default::default())?;

// 获取诊断接口(可以安全地移动到其他线程)
let diag = active.diagnostics();

// 在另一个线程中长期持有
thread::spawn(move || {
    // diag 在这里完全独立,不受主线程影响
    loop {
        // 执行诊断逻辑...
        std::thread::sleep(std::time::Duration::from_secs(1));
    }
});

// 主线程可以继续使用 active
// active.send_position_command(&target)?;

Structs§

PiperDiagnostics
高级诊断接口(逃生舱)

Type Aliases§

Result