# DevicePlugin — 统一设备管理插件 ## 概述 DevicePlugin 是 ShowenV2 的统一硬件访问层,负责管理所有设备相关的操作。通过抽象的 `DeviceBackend` trait,支持多平台适配(Linux ARM64、Android、Embedded 等)。 ## 架构 ``` 业务插件 (Video/Screen/BLE/HTTP/...) ↓ 发送 DeviceCommand DevicePlugin ↓ 分发给 Backend DeviceBackend (Linux/Android/Embedded) ↓ 硬件访问 硬件层 (Framebuffer/DRM/GPIO/I2C/SPI/...) ``` ## 支持的能力 DevicePlugin 通过 `DeviceCapability` enum 声明支持的硬件能力: - **Display**: 显示信息查询(分辨率、像素格式) - **Backlight**: 背光控制(开关、亮度) - **SleepInhibit**: 防息屏(通过 systemd-inhibit) - **Cursor**: 光标控制(显示/隐藏,通过 unclutter) - **Framebuffer**: 帧缓冲写入(待实现) - **Touch**: 触摸输入(待实现) - **Buttons**: 按钮输入(待实现) - **Audio**: 音频播放(待实现) - **Battery**: 电池状态(待实现) - **Sensors**: 传感器数据(待实现) - **GPIO**: GPIO 控制(待实现) ## 消息接口 ### DeviceCommand (业务插件 → DevicePlugin) ```rust pub enum DeviceCommand { // 显示 GetDisplayInfo, SetBrightness(u8), SetBacklight(bool), WriteFramebuffer { data: Vec, format: PixelFormat }, // 输入 GetTouchEvents, GetButtonState, GetSensorData(SensorType), // 音频 PlayAudio { path: String }, SetVolume(u8), // 电源 GetBatteryLevel, SetSleepInhibit(bool), // 光标 SetCursorVisible(bool), // 通用 CustomCommand { subsystem: String, payload: serde_json::Value }, } ``` ### DeviceResponse (DevicePlugin → 请求者) ```rust pub enum DeviceResponse { DisplayInfo { width: u32, height: u32, format: PixelFormat }, SensorData { sensor: SensorType, value: f64 }, BatteryLevel(u8), Ok, Error(String), Custom(serde_json::Value), } ``` ### DeviceEvent (DevicePlugin → 广播) ```rust pub enum DeviceEvent { TouchEvent { x: i32, y: i32, action: TouchAction }, ButtonEvent { button: u8, pressed: bool }, BatteryLow(u8), DisplayConnected, DisplayDisconnected, SensorAlert { sensor: SensorType, value: f64 }, } ``` ## 使用示例 ### 查询显示信息 ```rust let envelope = Envelope { from: "my_plugin".to_string(), to: Destination::Plugin("device".to_string()), message: Message::DeviceCommand(DeviceCommand::GetDisplayInfo), }; ctx.tx.send(envelope)?; // 接收响应 match message { Message::DeviceResponse(DeviceResponse::DisplayInfo { width, height, format }) => { println!("Display: {}x{} {:?}", width, height, format); } _ => {} } ``` ### 防息屏 ```rust // 启用防息屏 let envelope = Envelope { from: "my_plugin".to_string(), to: Destination::Plugin("device".to_string()), message: Message::DeviceCommand(DeviceCommand::SetSleepInhibit(true)), }; ctx.tx.send(envelope)?; // 禁用防息屏 let envelope = Envelope { from: "my_plugin".to_string(), to: Destination::Plugin("device".to_string()), message: Message::DeviceCommand(DeviceCommand::SetSleepInhibit(false)), }; ctx.tx.send(envelope)?; ``` ### 光标控制 ```rust // 隐藏光标 let envelope = Envelope { from: "my_plugin".to_string(), to: Destination::Plugin("device".to_string()), message: Message::DeviceCommand(DeviceCommand::SetCursorVisible(false)), }; ctx.tx.send(envelope)?; // 显示光标 let envelope = Envelope { from: "my_plugin".to_string(), to: Destination::Plugin("device".to_string()), message: Message::DeviceCommand(DeviceCommand::SetCursorVisible(true)), }; ctx.tx.send(envelope)?; ``` ## 与 ScreenPlugin 的关系 ### 历史背景 在 DevicePlugin 引入之前,ScreenPlugin 直接调用 `systemd-inhibit` 和 `unclutter` 命令来实现防息屏和光标隐藏功能。这导致: 1. **平台耦合**: ScreenPlugin 包含大量 Linux 特定代码 2. **重复实现**: 多个插件可能需要类似的硬件访问逻辑 3. **难以扩展**: 添加新平台需要修改多个插件 ### 迁移方案 (2026-03-13) **阶段二**完成了 ScreenPlugin 到 DevicePlugin 的功能迁移: 1. **DevicePlugin 扩展**: - 添加 `SetCursorVisible(bool)` 命令 - LinuxArm64Backend 实现光标控制(通过 unclutter) - 添加 `DeviceCapability::Cursor` 能力 2. **ScreenPlugin 重构**: - 改为 DevicePlugin 的 thin wrapper - 移除直接硬件操作代码 - 通过 `DeviceCommand` 消息实现所有功能 - 保持向后兼容的消息接口 3. **架构改进**: - 统一设备管理: 所有硬件访问通过 DevicePlugin - 平台解耦: ScreenPlugin 不再包含平台特定代码 - 消息驱动: 插件间通过消息通信,松耦合 ### 当前状态 - ScreenPlugin 保留作为兼容层,处理 `Message::ScreenLockRequest` 和 `Message::CursorVisibility` - 实际硬件操作由 DevicePlugin 的 LinuxArm64Backend 执行 - 未来可能完全移除 ScreenPlugin,业务插件直接使用 DeviceCommand ## 平台支持 ### Linux ARM64 (当前实现) - **Display**: 通过 DRM/KMS 查询显示信息 - **Backlight**: 通过 `/sys/class/backlight` 控制背光 - **SleepInhibit**: 通过 `systemd-inhibit` 防止系统休眠 - **Cursor**: 通过 `unclutter` 隐藏光标 ### Android (待实现) - Display: 通过 Android API 查询 - Backlight: 通过 Settings API 控制 - SleepInhibit: 通过 WakeLock - Cursor: N/A (触摸设备无光标) ### Embedded (待实现) - Display: 直接访问 framebuffer - Backlight: GPIO 控制 - SleepInhibit: 自定义电源管理 - Cursor: N/A (无操作系统) ## 测试 DevicePlugin 包含完整的单元测试和集成测试: ```bash # 运行所有测试 cargo test --package showen --lib plugins::device # 运行特定测试 cargo test --package showen --lib plugins::device::tests::test_set_cursor_visible ``` 测试覆盖: - 消息序列化/反序列化(DeviceCommand/DeviceResponse/DeviceEvent) - MockBackend 功能验证 - LinuxArm64Backend 能力声明 - ScreenPlugin ↔ DevicePlugin 消息流 ## 开发指南 ### 添加新的设备能力 1. 在 `DeviceCommand` 中添加新命令 2. 在 `DeviceCapability` 中添加新能力 3. 在 `LinuxArm64Backend::handle_command` 中实现命令处理 4. 在 `LinuxArm64Backend::capabilities` 中声明能力 5. 添加单元测试验证功能 ### 添加新的平台后端 1. 创建 `src/plugins/device/.rs` 2. 实现 `DeviceBackend` trait 3. 在 `src/plugins/device/mod.rs` 中注册后端 4. 添加平台特定的测试 ## 参考文档 - [DevicePlugin 设计文档](../../docs/DEVICE_PLUGIN_DESIGN.md) - [ScreenPlugin 迁移总结](../../docs/SCREEN_PLUGIN_MIGRATION_SUMMARY.md) - [集成测试文档](../../docs/DEVICE_PLUGIN_INTEGRATION_TEST.md)