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仍然处于特定状态 - 缓解:通过运行时检查和文档警告来保证安全
§使用场景
- 自定义诊断工具
- 高级抓包和调试
- 性能分析和优化
- 非标准回放逻辑
- 后台监控线程
§安全注意事项
此接口提供的底层能力可能破坏状态机的不变性。 使用时需注意:
- 不要在 Active 状态下发送控制指令(会导致双控制流冲突)
- 不要手动调用
disable()(应该通过Piper的Drop来处理) - 确保回调执行时间 <1μs(否则会影响实时性能)
- 注意生命周期:即使持有
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§
- Piper
Diagnostics - 高级诊断接口(逃生舱)