结论:Nissan safety 的核心是「变体先见即锁定」:get_addr_check_index() 在健康检查组内第一次看到某地址/总线/长度变体后就锁定其下标,之后只匹配该变体。对 Altima,如果错误接线或额外转发让 0x285 总线 0 先于所需的总线 1 到达,该组会锁到总线 0,而车型 RX 钩子只处理总线 1,后续车速不再被识别。另一条关键边界是:不在当前锁定变体内的帧,rx_msg_safety_check() 返回 true,但 safety_rx_hook() 的 whitelisted 为假,所以「返回有效不等于已消费」。TX 侧 0x169 受共享角度限制,而 0x280 Leaf 取消帧与 HUD 帧没有逐位载荷门。
初始化与总线变体锁定
nissan_init() 的 ALT_EPS_BUS 参数位只切换 RX 钩子预期的车速、踏板和巡航总线,构建同一 TX 白名单。get_addr_check_index() 在组内首次匹配时设置 msg_seen 与 status.index,之后只匹配该变体;safety_rx_hook() 要求变体有效且当前仍匹配才调用车型 RX 钩子。
nissan_rx_hook() 采样 0x185 转角、0x285 后轮速度、0x15C/0x239 油门、0x454/0x239 制动和 0x30F 原车巡航。在 ALT_EPS_BUS=1 时它从总线 1 读取 0x285、0x15C、0x454、0x30F;常规模式从总线 0 读取前三类、总线 2 读取巡航;0x185 转角始终要求总线 0。
RX:五组健康检查与「有效不等于被消费」
nissan_rx_checks 有五个健康检查组,各项均显式忽略校验和、计数器、质量位,仅以地址、长度、总线与名义频率/存活约束健康。
| 检查组 | 地址 | 允许总线 |
|---|---|---|
| 转角 | 0x185 |
0 |
| 后轮速度 | 0x285 |
0/1 |
| 巡航 | 0x30F |
2/1 |
| 油门 | 0x15C 或 Leaf 0x239 |
0/1 或 0 |
| 制动/状态 | 0x454 或 0x1CC |
0/1 或 0 |
源文档强调,这不是对每个 CAN 字段做完整性认证。Leaf 0x239 总线 0 的同一帧可更新油门与制动;它被放在油门健康检查组,制动组另有 0x1CC 变体,后者未被车型 RX 钩子直接解析为 brake_pressed。因此「健康表监视的消息」与「车型钩子消费的信号」不是完全一对一。
转角以 -0.01 度/位及偏置 1310 度解码到每度 100 单位;后轮双速取平均更新速度,任一原始后轮速度非零便视为在移动。原车巡航接合由 0x30F 输入巡航检查,其上升沿可使能、断开时退出。源文档提醒,新硬件不能将 Altima 总线、Leaf 踏板和 X-Trail 踏板归一成没有来源的旧值。
TX:转角、按钮与 Leaf 取消载荷
nissan_tx_hook() 对 0x169 从 CAN 位域解码目标角与 LKA_ACTIVE,用共享的转角命令检查:600 度绝对界限、随车速变化的起/退转角速率、测量角度及未使能中性状态。源文档强调这里是每度 100 原始单位,不是通用扭矩接口。对 0x20B 的附加判据只有 (data[1] & 0x3D) == 0:它禁止掩码内非取消按钮位,但不会逐位检查整帧或要求取消位必须为 1。
| TX 帧 | 检查强度 | 备注 |
|---|---|---|
0x169 |
解码目标角与 LKA_ACTIVE,运行共享角度限制 |
每度 100 原始单位,不是通用扭矩接口 |
0x20B |
仅检查 (data[1] & 0x3D) == 0 |
可在总线 2 或 Altima 总线 1 发送;check_relay=false |
0x2B1、0x4CC HUD |
无逐字段检查 | 总线 0 |
0x280 Leaf 取消 |
无逐字段检查 | 总线 2;探针中非零任意测试载荷仍通过 safety TX |
软件 create_acc_cancel_cmd() 会复制原车字段并覆盖按钮;Leaf create_cancel_msg() 会把 CANCEL_SEATBELT 置位,利用原车安全带告警退出巡航。源文档指出后者是驾驶员可感知的安全/HMI 行为,不能包装成普通、静默的取消插件。软件构帧约定也不能替代 MCU 逐位门:隔离探针中 0x280 的非零任意测试载荷仍通过 safety TX。
验证证据与插件边界
已有测试覆盖常规与 Altima 的转角/按钮基础行为,但源文档指出 Leaf 的按钮测试被明确跳过,不能证明 0x280 的 CANCEL_SEATBELT 载荷被硬件安全规则约束。本机新增探针以严格编译和 UBSan 通过按钮掩码、0x280 无载荷门及 Altima 错误总线先到锁定序列;未运行完整车型测试、目标编译器、实板或车辆 ECU 行为。
插件化时必须把 Nissan 平台、ALT_EPS_BUS、DBC、总线拓扑与取消方式绑定;0x280 及 HUD 原始帧应列为高权限输出,不能由任意插件直接构造。Nissan 未定义专属转发钩子,共享转发按当前 TX 表中 check_relay=true 的地址/目标总线阻断主机自身控制帧;0x20B 设置 check_relay=false,不应把它的白名单资格混同于静态阻断或原车报文真实性。
常见问题
为什么 Altima 的车速有时候识别不到?
因为健康检查组先见即锁定。源文档指出,若错误接线或额外转发让 0x285 总线 0 先于 Altima 所需的总线 1 到达,该组会锁到总线 0,而车型 RX 钩子仅处理总线 1,后续总线 1 车速不会被该组识别;本机隔离探针复现了这一序列。
健康检查通过是否说明车型已经消费了该信号?
不说明。源文档明确:不在当前锁定变体内的帧会让 rx_msg_safety_check() 返回 true,但 safety_rx_hook() 的 whitelisted 为假,车型状态不更新,因此「返回有效不等于已消费」。
0x280 Leaf 取消帧有逐位载荷校验吗?
没有。源码的 TX 白名单允许总线 2 的 0x280,但 nissan_tx_hook() 对它没有逐字段检查;源文档的隔离探针显示非零任意测试载荷仍通过 safety TX,因此它应列为高权限输出。
0x20B 的 check_relay=false 是否等于原车报文可信?
不等于。0x20B 设置 check_relay=false,源文档提示不应把它的白名单资格混同于静态转发阻断或原车报文真实性;共享转发只按 check_relay=true 的地址与目标总线阻断主机自身控制帧。
延伸阅读
- Chrysler / Nissan / Mazda 安全模式对照 —— 同批多品牌 safety 的横向比较。
- Toyota panda safety 模式 —— 另一家车厂的 RX/TX 门与总线约束。
- Ford panda safety 模式 —— 对照白名单与逐位检查的设计差异。
- panda 健康 ABI 与版本映射 —— 健康变体与主机侧版本的对应关系。
参考资料
- 项目 02 ——
openpilot-research/NISSAN_PANDA_SAFETY_MODE_DEEP_DIVE.md(取用了 RX 五组健康检查表、变体锁定语义、TX 帧检查强度表、Leaf 取消载荷与探针结果)。
说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。
更新记录
首次发布 2026-10-11 最近核对:2026-10-11