结论:这四个实时诊断 CLI 不是只读日志分析器:它们都经 sendcan 向车辆发送诊断帧,其中 disable_ecu.py 会请求改变 ECU 通信状态。判断结果是「脚本打印」还是「目标 ECU 真的接受」,是两条不同层级的问题——发布成功只表示请求进入了发送链,能否真正上总线还取决于 pandad 与 panda 固件状态。多个工具还会读写 Params、切换 OBD 复用,且没有 finally 恢复。固定快照基线为 c8fb906,本文未执行脚本、连接车辆或发送 CAN。
共同调用链
四个 CLI 都调用 can_comm_callbacks():从 can 读取 CanData,把请求封装为 sendcan Event。后者被 can_send_thread() 接收并交给 panda;能否真正上总线还取决于 pandad 与 panda 固件状态。不能把「脚本打印结果」或「发布成功」直接等同于目标 ECU 接收成功。
| 入口 | 请求与输出 | 本机状态变化 |
|---|---|---|
ecu_addrs.py |
默认 bus 1、超时 1 秒;生成 256 个 11-bit 和 256 个 29-bit 候选地址,批量发送 tester-present;仅打印响应地址及可选子地址。 | 删除 FirmwareQueryDone,IsOffroad 写真、等 0.2 秒再写假;依 --no-obd 切换 OBD 复用。 |
vin.py |
默认 bus 1、单次超时 0.1 秒、最多 5 轮;尝试该总线允许的 UDS / OBD 或品牌特例,打印响应地址、bus 和 VIN。 | 脚本本身不写 Params、不切 OBD 复用;仍向 sendcan 发诊断请求。 |
fw_versions.py |
先查 bus 0/1 的 VIN,再查品牌固件,输出原始版本字节及可能车型;--brand 只缩小固件查询范围。 |
同样删除 / 改写 Params;VIN 前先请求 OBD 复用,固件请求期间可逐请求切换。 |
disable_ecu.py |
固定在 bus 1 向 Honda Bosch 雷达地址请求扩展会话,再发送通信控制请求;打印布尔值。 | 不写 Params、不切 OBD 复用;会尝试改变目标 ECU 的收发状态,且没有恢复调用。 |
OBD 复用与状态位
obd_callback() 在目标模式与 Params 当前值不同时,删除 ObdMultiplexingChanged、写 ObdMultiplexingEnabled,然后无独立期限地阻塞等待确认;pandad 的 updateMultiplexingMode() 在实际切换后写确认。ECU 地址与固件脚本没有恢复先前 Params / OBD 状态的路径。
FirmwareQueryDone 被删除后,pandad 的 fetchCarParams() 会拒绝继续取得车辆参数,直到其他流程重新置位;常规 Car.__init__() 会在车型识别后置位。IsOffroad 的真 / 假写入是脚本行为,不能据此断言 pandad 已同步切换安全模式——其安全模式配置使用 deviceState.started。
| 工具 | 是否读写 Params | 是否切 OBD 复用 | 是否恢复原状态 |
|---|---|---|---|
ecu_addrs.py |
删除 FirmwareQueryDone,改写 IsOffroad |
是(--no-obd 控制) |
否(无 finally) |
vin.py |
否 | 否 | 不适用 |
fw_versions.py |
删除 / 改写同 ECU 地址脚本 | 是(VIN 前与固件期间) | 否 |
disable_ecu.py |
否 | 否 | 否(改 ECU 收发状态且无恢复调用) |
失效与证据边界
--scan当前不可用。 脚本把 256 组三种地址形状放进extra={"any": {"debug": extra}},但固件查询按品牌执行FW_QUERY_CONFIGS[brand];当前归档没有any品牌配置。因此 VIN 查询和 Params / OBD 副作用已经发生后,固件地址构建阶段抛KeyError('any');--brand也不会消除此额外键。- ECU 清单不是全量证明。
get_all_ecu_addrs()把 TX 候选集合直接当 RX 白名单;29-bit 响应通常采用交换后的地址,可能被过滤。get_ecu_addrs()捕获异常后返回已收集的部分集合,timeout也不能限制阻塞式接收的整个墙钟时间。 - VIN 既不验证身份,也不保证隐藏。
get_vin()对命中地址的结果做少量去填充后直接解码返回,CLI 原文打印 VIN。失败时返回(-1, -1, "00000000000000000"),不等同于「车辆没有 VIN」;源码另有is_valid_vin(),此 CLI 没有调用它。 - 固件列表可以是部分结果。 固件查询按请求配置与子地址分组,单个请求异常记录后继续;返回版本可能缺 ECU 或缺品牌。候选车型匹配给的是候选集合,不是执行许可。原始固件字节与 VIN 可能包含可识别车辆的信息。
- 手动禁用雷达不确认禁用成功。 通用
disable_ecu()最多重试 10 次,先要求扩展会话的有效应答,再调用get_data(0)发送通信控制请求并丢弃返回字典;零超时和空的期望响应前缀不能提供可靠的正响应证据。帮助函数注释明确警告会禁用原车 AEB,脚本没有配套恢复路径。
面向硬件与插件化的接口约束
以下是设计建议,并非当前实现:将前三类查询工具改为只提交有界诊断任务的证据插件,sendcan 与 OBD 复用由唯一诊断代理持有。代理校验点火 / 车速、bus、地址、服务、速率和总时长,记录每次请求与局部响应;--scan 需先修复配置建模,再在隔离台架验证总线负载。通信控制应归入单独的高危能力,需要目标 ECU / 版本白名单、原车 AEB 影响评估、正响应和总线状态回读、持续保活及恢复方案。身份插件只返回带来源和时间戳的 VIN / 固件证据,不提供控制权限;执行权限仍由独立 MCU / panda safety 和车型适配门决定,不能由插件加载或候选车型自动授予。
常见问题
这些 CLI 会向车辆发 CAN 吗?
会。四个工具都经 sendcan 向车辆发送诊断帧,其中 disable_ecu.py 会请求改变目标 ECU 的通信状态。它们不是只读日志分析器;「脚本打印结果」不等同于目标 ECU 接收成功。
运行这些脚本会留下什么状态?
ECU 地址与固件脚本会删除 FirmwareQueryDone,把 IsOffroad 写真、等 0.2 秒再写假,并切换 OBD 复用,且没有恢复先前 Params / OBD 状态的 finally。FirmwareQueryDone 被删后,pandad 会拒绝继续取得车辆参数直到重新置位。
–scan 现在能用吗?
不能。脚本把地址形状放进 extra={"any": ...},但固件查询按品牌执行 FW_QUERY_CONFIGS[brand],当前归档没有 any 品牌配置,固件地址构建阶段会抛 KeyError('any');--brand 也不会消除该额外键。VIN 查询和 Params / OBD 副作用已经发生。
打印 disabled: True 就说明雷达被禁用了?
不能这样认为。通用 disable_ecu() 丢弃查询结果,零超时与空期望响应前缀无法提供可靠的正响应证据;即使底层打印成功,也不等于已证实 ECU 停发、AEB 状态或会话保持。帮助函数注释明确警告会禁用原车 AEB。
延伸阅读
- UDS 诊断工具为什么不能随手调:只读、会话与写 ECU 的分权设计 —— 解释通信控制为何属于高危写操作。
- ECU 诊断传输层:ISO-TP 分段与超时 —— 承接本文的长帧传输与超时边界。
- 车型指纹与固件匹配:识别链上的两道关口 —— 与固件查询 / 候选车型匹配直接衔接。
- 车型平台参数契约:CarParams 是怎么被填出来的 —— 说明
FirmwareQueryDone与车型识别的关系。
参考资料
- 项目 02 ——
openpilot-research/CAR_LIVE_DIAGNOSTIC_CLI_CONTRACT_DEEP_DIVE.md(取用了四个 CLI 的请求与副作用、失效边界与插件化接口约束分析)。
说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。
更新记录
首次发布 2026-10-11 最近核对:2026-10-11