Files
ShowenV2/src/plugins/device
showen 3729addb71 docs: DevicePlugin阶段二 Task5 — 文档更新与迁移总结
- 更新 DEVICE_PLUGIN_DESIGN.md: 阶段二标记完成+验收项勾选+成果章节
- 新建 src/plugins/device/README.md: 完整DevicePlugin文档
- 新建 docs/SCREEN_PLUGIN_MIGRATION_SUMMARY.md: 迁移总结
- 更新 li-siqi soul + TEAM_CHAT 汇报

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 12:39:25 +08:00
..

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)

pub enum DeviceCommand {
    // 显示
    GetDisplayInfo,
    SetBrightness(u8),
    SetBacklight(bool),
    WriteFramebuffer { data: Vec<u8>, 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 → 请求者)

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 → 广播)

pub enum DeviceEvent {
    TouchEvent { x: i32, y: i32, action: TouchAction },
    ButtonEvent { button: u8, pressed: bool },
    BatteryLow(u8),
    DisplayConnected,
    DisplayDisconnected,
    SensorAlert { sensor: SensorType, value: f64 },
}

使用示例

查询显示信息

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);
    }
    _ => {}
}

防息屏

// 启用防息屏
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)?;

光标控制

// 隐藏光标
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-inhibitunclutter 命令来实现防息屏和光标隐藏功能。这导致:

  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::ScreenLockRequestMessage::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 包含完整的单元测试和集成测试:

# 运行所有测试
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/<platform>.rs
  2. 实现 DeviceBackend trait
  3. src/plugins/device/mod.rs 中注册后端
  4. 添加平台特定的测试

参考文档