编辑 | blame | 历史 | 原始文档

CAN 全局应答器 + 硬件调试页多设备并发 — 设计规格

日期:2026-11-09
状态:已与用户逐节确认
关联基线:CAN 模拟器 TCP 服务化 + 统一 CanDeviceDriver(已完成,47 单测通过)

1. 需求

两个独立特性:
- 特性一(应答器):当前"自动响应"仅在"有第二个节点且该节点开了自动响应"时才回复。
用户需要:客户端单独发一条请求,模拟器就能自动回复,无需第二节点。
- 特性二(多设备并发调试):硬件调试页(DeviceDebug)当前单设备单会话,
用户需要同时在多个 Tab 里调试多个 CAN 设备,各自独立会话与维护租约。

2. 已确认决策

点 结论
应答器语义 总线级开关,把发送帧回显给发送者(回波),无需第二节点
应答内容 回显同帧(相同帧ID+数据),来源标记 RESPONDER
应答器开关入口 服务窗口每总线一个复选框;并支持命令 BUS_ECHO:ON/OFF
与节点自动响应关系 二者独立并存,互不触发、互不干扰,用户按需开启
多设备形态 DeviceDebug 改为 TabControl,每 Tab 一个 DeviceDebugTab,各自独立会话
一会一设备 设备下拉只列未打开设备;已打开则聚焦其 Tab,不重复开会话
会话生命周期 加入→OpenSession(ReadOnly);关 Tab→CloseSession(经 token 缓存复用正常释放维护租约)
设备范围 通用(CAN/电源/PLC 同结构),主场景多个 CAN;复用 LoadPanel(kind)

3. 特性一设计:总线级应答器

3.1 CanBusSimulator

  • 新增 public bool EchoResponderToSender { get; set; }(默认 false)。
  • OnNodeFrameSent 路由末尾:若 EchoResponderToSender 且源节点存在,
    复制该帧投递回**源节点自身**(sourceNode.ReceiveFrame(echoCopy),直接调用绕过"不回源"),
    回显帧 SourceNodeId = "RESPONDER",Timestamp = now,FrameId/Data 同原帧。
  • 与现有 SendAutoResponse(接收节点回复别人)互不影响:应答器面向"发送者回环",
    节点自动响应面向"接收者答复"。

3.2 命令与 UI

  • CanCommandExecutor 增加 BUS_ECHO 查询:BUS_ECHO:ON|OFF 设置 _bus.EchoResponderToSender;
    裸 BUS_ECHO 查询当前状态,返回 OK:BUS_ECHO:ON|OFF。
  • 服务窗口 MainWindow 每总线节点行/工具区加"应答器"复选框,绑定 CanBusSimulator.EchoResponderToSender。
  • 传输/驱动层零改动:命令走既有 QUERY: 通道(Local 直发 / Broker 经 RPC 到宿主再转 TCP)。

3.3 数据流

客户端 SEND:0x100:AA → 服务端路由 → (应答器开) 回显帧 EV:RECV:0x100:AA:...:RESPONDER
   → 同一 TCP 连接推送回发送节点 → 客户端 DriverFrameReceived 上屏(来源 RESPONDER)

无额外轮询;与节点自动响应同用一路事件模型,不产生重复行(来源不同)。

4. 特性二设计:DeviceDebug 多标签多会话

4.1 结构

DeviceDebug(壳)
 ├─ 顶栏:设备下拉(仅未打开设备) + [加入调试] + [关闭当前页]
 └─ TabControl
     └─ DeviceDebugTab × N(新 UserControl,自带独立会话)
          · 绑定自身 CurrentDeviceId / ConnectionState / SessionState / Reservation / CanEnter|ExitMaintenance
          · panelContainer:LoadPanel(kind)(CAN→CanDebugPanel 壳;PowerSupply;PLC)
          · 自身操作日志
          · 进入/退出维护只作用于本设备会话(sessionId 复用 token,逻辑沿用 DebugSessionManager)

4.2 会话与租约

  • DebugSessionManager 不改:_activeSessions 已按 sessionId、GetActiveSessionByDevice
    按设备支持多设备并发会话。
  • 每 DeviceDebugTab 持有一个 sessionId,调用 OpenSession/RequestMaintenance/ActivateMaintenance/ CloseSession,各自资源键为自身 deviceId → 不同设备租约天然独立、无冲突。
  • 关闭 Tab 必须 CloseSession(正常释放维护租约,杜绝 Token 泄漏型"第二次进维护失败")。
  • 同设备不可能出现两个 Tab(下拉过滤 + 聚焦既有 Tab 拦截)。

4.3 迁移与影响面

  • DeviceDebug.xaml:把现"信息栏+维护按钮+panelContainer+操作日志"整体移入 DeviceDebugTab;
    DeviceDebug 顶层改为 顶栏 + TabControl。
  • DeviceDebug.xaml.cs:拆分——壳负责设备列表/加入/关闭 Tab 路由;
    原单会话状态机方法迁入 DeviceDebugTab.xaml.cs(每个 Tab 一个实例)。
  • 对外契约(插件入口 InitFinish、ForceRefreshForTest)保留在壳上,行为不变。
  • 现有 CAN 通道事件接收、应答器、Broker 代理均复用,无回退。

5. 测试策略

  • 单测(应答器):SimulatorServerCoreTests 增例——开 BUS_ECHO:ON 后单节点 SEND 收到
    来源 RESPONDER 的回显;关后无回显;与节点自动响应并存时来源区分正确、无重复帧。
  • 单测(命令):BUS_ECHO:ON/OFF/查询 走通 CanCommandExecutor;Broker 经 RPC 亦生效。
  • DeviceDebug 多会话为 UI 重构,以 MSBuild 编译 + 手动验收覆盖:
    同时开 CAN-001/002/003 三个 Tab,各自进入维护互不阻塞;关闭某 Tab 后其设备可再次进入维护
    (证明租约正确释放);应答器开启后任一 Tab 单独发帧即收到回显 RX。
  • 回归:现有 47 单测保持全绿。

6. 构建与约束

  • 沿用 VS 完整版 MSBuild 编译 WPF 链路(不加 /p:Platform=x64);
    服务端核心可用 dotnet。
  • 不引入新外部依赖;应答器仅在 CanSimulator 库与执行器内扩展,Broker/驱动层不动。