结论:panda 板级固件不是一个「CAN 转发器」。主机候选发送、车辆报文接收、板内总线转发是三条独立路径,各自经过不同的安全门与回执机制。启动时安全模式先被置为 SILENT,只有车型模式才驱动拦截继电器;而 1 Hz 的 safety_tick() 只做超时、最低频率与有效性的巡检,不能当成毫秒级断线检测。本文为固定源码归档的静态阅读,未编译固件、未连接实板。
三条 CAN 路径与各自的安全门
把三条路径混为一谈,是理解 panda 安全边界时最常见的错误。主机写入的候选帧、车辆发来的报文、以及板内转发,处在不同的钩子和不同的准入条件之下。
| 路径 | 关键调用链 | 安全语义 |
|---|---|---|
| 主机候选发送 | pandad::can_send_thread() → comms_can_write() → can_send(..., false) → safety_tx_hook() → process_can() |
主机先丢弃超过 1 秒的 sendcan;板端每个完整 CAN 包经过 TX 白名单、车型限值和继电器故障门。被拒帧作为 rejected 回执进入 RX 队列,不会进 TX FIFO。 |
| 车辆报文接收 | can_rx() → safety_rx_hook() → comms_can_read() → pandad::can_recv() |
板端先从 FDCAN FIFO 取帧并附 bus/长度/FD 标志;安全 RX 仅对通过对应检查和白名单的帧调用车型状态钩子。 |
| 板内总线转发 | can_rx() → safety_fwd_hook() → can_send(..., true) |
转发准许由独立的 safety_fwd_hook() 决定;true 表示跳过主机发送的 TX 钩子。当前代码在 safety_rx_hook() 之前计算转发并入队,因此不能声称接收帧必须先通过 RX 有效性检查才会被转发。 |
safety_fwd_hook() 默认只映射 0↔2;继电器故障或模式设置 disable_forwarding 时阻断,并静态屏蔽需由 openpilot 替代发送的原车报文。另有细节:主机 CAN 组包维护跨传输分片的缓存,comms_can_reset() 在连接重建时清空它,避免半包污染下一连接。
启动顺序也值得单独看:main() 先将安全模式设为 SILENT,再启用收发器、定时中断和 USB/SPI。主机侧 PandaSafety::fetchCarParams() 要求 FirmwareQueryDone、ControlsReady,随后 setSafetyMode() 发送安全模式和参数。这道门是启动协调,不是对任意主机代码或插件的独立授权机制。
三条路径共享同一套健康上报(get_health_pkt())与继电器状态,但准入条件各不相同,这正是「主机能发」与「板端放行」必须分开验证的原因。
安全模式与心跳:秒级兜底不是唯一保护
安全模式不是普通运行时插件可任意替换的配置,切换会影响继电器和 CAN 队列,必须按车型、固件和线束验证。
| 函数/状态 | 当前实现 | 硬件含义 |
|---|---|---|
set_safety_mode() |
调用 set_safety_hooks();未知模式退回 SAFETY_SILENT,连 SILENT 初始化都失败则停止。 |
SILENT/NOOUTPUT/ELM327 释放拦截继电器;车型模式才驱动继电器再初始化 CAN。 |
set_safety_hooks() |
注册模式、重置安全状态。MG、PSA、BYD、Subaru Preglobal、Volkswagen MLB/PQ、ALLOUTPUT 等仅在 ALLOW_DEBUG 编译块注册。 |
有目录和测试不代表 release 固件可选择该安全模式;必须核对实际固件构建与主机 safetyConfigs。 |
safety_tx_hook() |
车型模式检查地址、bus、长度白名单及车型 TX 约束;继电器故障会否决。 | 「panda 永远过滤任意主机帧」是错误表述;诊断与调试模式不具备车型执行边界。 |
safety_tick() |
每秒检查期望 RX 报文的超时、最低频率和有效性,异常时清 controls_allowed。 |
不能将 1 Hz 巡检误写为毫秒级断线检测。 |
tick_handler() |
8 Hz 调用风扇、线束、软件看门狗;1 Hz 处理点火、心跳、safety_tick()。点火时主机心跳 5 秒未到、非点火时 2 秒未到,切 SILENT。 |
心跳退出是秒级兜底,不是新硬件对快速危险动作的唯一保护。 |
get_health_pkt() |
上报安全模式、参数、心跳、RX/TX 拦截计数、队列溢出、CAN 错误、线束状态、电压/电流/温度。 | 主机应把健康状态和车型配置对齐,而不是仅判断 USB 在线。 |
通信、线束与物理边界
这些边界决定了「代码静态链路」与「电气默认态」之间的差距。队列里的 XOR 校验只保证主机与固件之间的传输完整性,与车型 CAN 报文自身的 checksum 不是一回事。
| 组件 | 函数/实现 | 设计观察 |
|---|---|---|
| CAN 队列与校验 | can_push()、can_pop()、can_set_checksum() |
RX/TX 使用临界区环形队列;队列满时累计溢出。包内 XOR 是传输完整性检查,不等于车型 CAN 报文 checksum。 |
| 线束方向与继电器 | harness_detect_orientation()、set_intercept_relay() |
SBU 电压判断正反插;方向改变时重新映射 bus、初始化 CAN 和安全模式。实际断电默认态须以原理图和台架证明。 |
| 控制请求 | comms_control_handler() |
USB/SPI 命令能设安全模式、CAN 速率、FD 行为、继电器、心跳和电源;0xc5 继电器控制在代码中并无 ALLOW_DEBUG 条件(注释写 DEBUG)。 |
| 启动完整性 | bootstub.main() |
验证应用长度、版本、SHA 与 RSA 发布签名;启动签名约束固件映像,不代表运行时 USB 控制命令已获得逐操作鉴权。 |
电源与错误恢复另有边界:set_power_save_state() 省电时关部分中断/收发器但保留主总线用于点火检测,源码明确要求安全功能执行期间不进入硬件低功耗模式;FDCAN 的发送前包校验、总线 off、RX FIFO 丢失与 ACK 错误会进入健康计数与控制器恢复路径,CAN FD/BRS 可由收到的帧检测并改变总线配置。现有测试入口包括车型安全单元测试、USB 协议测试,以及 HITL 的线束、CAN 回环与延时、NOOUTPUT 三组;本地归档未连接实板、也未运行这些测试,代码静态链路不证明电气默认态或故障覆盖率。
自研车端网关的最低验收点
- 先复现
SILENT启动、未知模式回退、车型 RX/TX/转发独立门、报文来源总线与长度、心跳丢失、原车 ECU 冲突检测;插件只可提交受限候选命令,不可获得原始控制端点。 - 分别注入心跳超时、软件 tick 间隔故障、FDCAN bus-off、队列满、主机失联、线束正反插与电源断开;记录 MCU 输出、继电器触点与原车总线波形,不能只看
health_t计数。 - 板型
red、tres、cuatro的 GPIO/收发器/供电差异要逐板核对;PANDA_CAN_CNT=3与线束方向映射只是当前实现,不应直接推导新 PCB 的引脚或额定参数。 - 固件签名、版本、发布/调试模式、主机权限和可升级回滚是共同边界;不能用调试固件测试结果替代发布固件证据。
常见问题
panda 的 1 Hz safety_tick() 能替代毫秒级断线检测吗?
不能。safety_tick() 每秒检查期望 RX 报文的超时、最低频率和有效性,异常时清 controls_allowed,其丢帧容忍窗口偏保守。它是秒级巡检,额外的主机超时、CAN 控制器故障与硬件失效仍需单独验证。
主机发送的每一帧都会被 panda 无条件过滤吗?
不是。车型模式检查地址、bus、长度白名单及车型 TX 约束,但 ELM327 和调试固件的 ALLOUTPUT 特例会把白名单视为通过。因此「panda 永远过滤任意主机帧」是错误表述,诊断与调试模式不具备车型执行边界。
为什么板内转发不经过 safety_tx_hook()?
因为转发以 can_send(..., true) 调用,true 跳过主机发送的 TX 钩子,其准入由独立的 safety_fwd_hook() 决定(默认只映射 0↔2)。这与 USB/SPI 客户端经 can_send(..., false) 的发送许可不是同一机制。
固件签名能保证运行时 USB 命令被逐操作鉴权吗?
不能。启动签名只约束固件映像;运行时控制命令的准入需主机与通信入口另行约束,USB/SPI 控制请求应纳入可信计算基,不应直接向第三方插件暴露。
延伸阅读
- 从使能到车轮:执行链上的八道门,以及它们各自不保证什么 —— 解释 TX 白名单准入为何不等于继电器与 ECU 的最终执行。
- CAN 报文解析的「健康位」在说什么:校验、计数器与总线空窗 —— 与本文 RX 有效性门和健康计数相互印证。
- panda bootstub 的签名与刷写边界 —— 承接本文启动完整性与发布/调试签名差异。
- Ford panda 安全模式:双车速、曲率与纵向权限 —— 看具体车型如何挂接 RX/TX 钩子与白名单。
- UDS 诊断工具为什么不能随手调:只读、会话与写 ECU 的分权设计 —— 承接控制系统入口的权限分层。
参考资料
- 项目 02 ——
openpilot-research/PANDA_BOARD_DEEP_DIVE.md(取用了三条 CAN 路径与安全门、安全模式与心跳、通信/线束/物理边界,以及自研网关验收点)。 - 项目 02 ——
openpilot-research/CAR_PROTOCOL_IMPLEMENTATIONS.md(仅用于确认车型差异与插件契约的引用位置)。
说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。
更新记录
首次发布 2026-10-11 最近核对:2026-10-11
发表回复