结论:Toyota 的固件指纹识别是三级顺序匹配:先精确固件匹配,再通用「至少两个唯一 ECU」模糊匹配,最后才调用品牌自定义的平台码回退。平台码只比较「零件号-平台-主版本」键,不比较子版本,所以小版本更新仍可能命中旧车型数据库;而「模糊」只是容忍子版本差异,并不容忍任意 ECU 集合。候选不唯一时必须保持被动或人工核验,不能在控制插件里猜。
平台配置不是运行时健康
CAR 的每个枚举成员包含 CarSpecs、车型文档、动力/雷达 DBC 映射和静态 flags。构造平台时执行配置 init(),创建 CAR 枚举时写入平台名并冻结配置对象——这是一份冻结的静态表,不是运行时健康状态。
几个容易混淆的映射:TSS2 配置默认指向 toyota_nodsu_pt_generated 和 toyota_tss2_adas;SecOC 配置改用 toyota_secoc_pt_generated。若配置含 RADAR_ACC,两个配置类都只留下动力 DBC,表示本快照不按对应雷达 DBC 解析该路径——不能推论车辆没有物理雷达。
同理,ToyotaCarDocs 默认标注 Toyota A 线束,SecOC 车型文档另用 CUSTOM 支持类型。源文档强调:文档展示字段、DBC 可用性、CarParams.radarUnavailable 和实车传感器健康是四个不同维度。EPS_SCALE 对大多数车型默认 73,少数车型显式覆盖;它进入 Toyota safety 参数低字节与状态侧 EPS 扭矩缩放,不能作为插件自报的可信运行标定。
固件查询的实际覆盖
FW_QUERY_CONFIG 声明三组总线 0 诊断请求,各组有独立 ECU 白名单:
| 组别 | 请求流程 | 边界 |
|---|---|---|
| KWP | tester-present 后查询 0x1a8801 |
与其他组共享 ECU 白名单机制 |
| OBD 版本 | 短 tester-present 后查询 OBD 版本 | 独立白名单 |
| UDS 版本 | tester-present / 默认会话 / 扩展会话后查询 UDS 版本 | 独立白名单 |
其中 extra_ecus 只列出额外可查地址,并不表示都参与模糊匹配;部分车型的 ABS 或发动机 ECU 被列为 non_essential_ecus,用来处理缺报或多地址。源文档特别提醒:不能把「可缺席」理解成「该 ECU 的所有错误版本都允许通过」,具体精确匹配语义由通用的 match_fw_to_car_exact() 实施。
匹配顺序:精确、通用模糊、品牌回退
通用识别顺序是固定的三级,越靠后越宽松,但每一级都不做「最像的一款」打分:
| 阶段 | 条件 | 结果处理 |
|---|---|---|
| 精确固件匹配 | 固件版本与数据库精确命中 | 返回是否精确及候选集 |
| 通用唯一 ECU 模糊匹配 | 「至少两个唯一 ECU」 | 可返回多个候选 |
| Toyota 平台码回退 | 仅当前品牌在模糊阶段尚无候选时调用 | 返回所有通过的候选 |
关键规则在 get_car():只有固件候选恰好一个时,才用它覆盖 CAN 指纹结果;零个或多个候选则保留 CAN 识别结果,显式固定车型设置又可覆盖两者。源文档明确这里没有把唯一固件候选与 CAN 指纹做一致性合取。此外,match_fw_to_car_fuzzy() 虽然接收 vin 参数,但 Toyota 此实现没有读取该参数——VIN 字符串不能消解平台码歧义。
平台码算法逐步拆解
get_platform_codes() 从固件字节提取零件号/平台/主版本键,并保留子版本集合。它的步骤可以逐条核对:
- 检查首字节是否为
0x01至0x03的块数;未命中则按单块处理。 - 总字节长度必须等于块数乘 16,否则跳过该固件。
- 每块去掉头尾零和空格,但仅解析第一块;第一块长度 8、10、12 时分别尝试 short、medium、long 正则,且正则使用
search(),不是额外的全字节锚定校验。 - 返回字典键为
platform-major(短格式)或part-platform-major(中/长格式),值是子版本集合。 - 第二块和子版本可被保留或解析出来,却不参与最终车型键比较——因此小版本更新可以命中旧车型数据库。
在模糊匹配阶段,match_fw_to_car_fuzzy() 对每个候选车型遍历数据库里类型属于 fwdCamera、fwdRadar、eps 的 ECU,以地址/子地址从实车固件表取版本;每个预期 ECU 至少要找到一个平台键,否则该候选失败;通过的部分必须覆盖候选的这些预期地址。最后减去 FUZZY_EXCLUDED_PLATFORMS——该集合在本快照为空。
歧义与插件契约
跨地址、漏回包、固件格式异常会导致匹配缺席;共享平台/主版本键则可能导致多个候选。源文档对此的定性很直白:这里的「模糊」是容忍子版本差异,不是容忍任意 ECU 集合,更不是把单条相机固件当作充分身份凭证。
对于硬件自制或插件化平台,错误识别会连带选择错误的 DBC、转向模式和 safety 参数。因此源文档提出一条比现状更严格的拟议契约:车型识别服务应返回 CAN 候选、固件候选及其交叉一致性、证据 ECU/地址/原始回包、精确或模糊等级、冲突原因和数据集版本;安全核心在候选唯一、且 DBC/固件/safety 组合得到验证前,保持 noOutput。这是重构建议,不是当前行为。
测试层面,test_toyota.py 检查角度/RADAR_ACC 标志属于 TSS2、当前 LTA 车型集合、TSS2 动力 DBC、必要 ECU 项和固件格式,并遍历数据库版本检查专属回退的唯一性与排除集合。但这只证明「现有固件数据库样本」受到约束,不能证明未知地区、替换 ECU 或故意构造的相似固件不会误识别;且本轮未运行这些测试。
常见问题
为什么小版本固件更新后还能识别成同一车型?
因为 get_platform_codes() 返回的键只到「零件号-平台-主版本」,值是子版本集合,而子版本不参与最终车型键比较。第二块和子版本可被保留或解析出来,却不会被用来区分车型,所以小版本更新可以命中旧车型数据库。
固件匹配失败一定会退回到品牌专用逻辑吗?
不一定。顺序是精确固件匹配、通用模糊匹配,最后一层才调用 Toyota 自定义平台码回退,而且仅当当前品牌在模糊阶段尚无候选时才调用。若前面的阶段已经返回候选,就不会进入品牌回退。
VIN 能帮助消除固件候选歧义吗?
在这份实现里不能。match_fw_to_car_fuzzy() 虽然接收 vin 参数,但 Toyota 该实现没有读取该参数,因此 VIN 字符串不能消解平台码歧义。
多个固件候选时,最终选哪个车型?
get_car() 只有在固件候选恰好一个时才用它覆盖 CAN 指纹结果;零个或多个候选则保留 CAN 识别结果,显式固定车型设置又可覆盖两者。源文档说明这里没有把唯一固件候选与 CAN 指纹做一致性合取,因此歧义不会被自动「合取」消解。
延伸阅读
- 17 个车型目录与 DBC 编解码:车型指纹为什么不能只看一条报文 —— 承接 CAN 指纹与 DBC 编解码的整条链路。
- 车型指纹与固件匹配:识别链上的两道关口 —— 同一识别链上精确与模糊分级的另一视角。
- 84% 的 PID 没有公开证据:OBD 私有协议解析的现实边界 —— 说明平台/固件证据为何必须以实测为准。
- CAN 报文解析的「健康位」在说什么:校验、计数器与总线空窗 —— 匹配依赖的回包质量与总线健康语义。
参考资料
- 项目 02 ——
openpilot-research/TOYOTA_PLATFORM_FIRMWARE_MATCHING_DEEP_DIVE.md(取用了 FW_QUERY_CONFIG 三组请求、三级匹配顺序、平台码算法步骤与拟议插件契约)。 - 项目 02 ——
openpilot-research/CAR_PROTOCOL_IMPLEMENTATIONS.md(仅用于确认match_fw_to_car()与get_car()在整条识别链中的位置)。
说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。
更新记录
首次发布 2026-10-11 最近核对:2026-10-11
发表回复