4、SOME/IP与DoIP的协同场景:OTA升级中的协同工作

OTA升级,说白了就是给车“打补丁”。

这活儿看着简单,实际坑特别多。我参与过好几个量产项目的OTA方案设计,每次都会遇到SOME/IP和DoIP怎么配合的问题。今天咱们就聊聊这个。

4.1 OTA升级的通信需求拆解

先想清楚一件事:OTA升级到底需要什么通信能力?

  • 控制面:升级指令、状态查询、版本信息——这些数据量小,但要求实时可靠
  • 数据面:固件包传输——数据量大,动辄几百MB甚至几个GB
  • 诊断面:刷写过程中的诊断会话控制、安全访问——这是DoIP的老本行

你想想看,如果只用SOME/IP传固件包,那效率太低了。如果只用DoIP做状态监控,又不够灵活。所以,两者必须协同。

核心思路:DoIP负责“管道”和“安全”,SOME/IP负责“业务逻辑”和“服务发现”。

4.2 协同工作的典型流程

我习惯把OTA升级分成三个阶段。每个阶段,SOME/IP和DoIP的分工都不一样。

阶段一:升级准备

这个阶段主要是发现车辆、建立连接、获取车辆信息。

  1. DoIP车辆发现:用UDP广播的VIN请求,找到目标ECU。嗯,这里要注意,DoIP的车辆声明消息里会携带VIN和EID,这是后续通信的基础。
  2. SOME/IP服务发现:通过SD(Service Discovery)找到OTA Master提供的升级服务。我记得有一次调试,发现SD的OfferService报文一直收不到,最后查出来是TTL配置太短了。
  3. 会话建立:DoIP建立TCP连接,切换到扩展诊断会话。同时SOME/IP订阅OTA服务的Eventgroup。

个人经验:我建议在DoIP的RoutingActivation之后,先不要急着发SOME/IP报文。等DoIP的DiagnosticMessage通道确认可用,再启动SOME/IP的SD。否则容易出现“服务找到了,但数据通道没准备好”的尴尬局面。

阶段二:固件传输

这是最核心的阶段,也是协同工作的难点。

为什么难?因为固件传输既要快,又要稳,还要安全。

我见过两种主流方案:

方案 传输通道 控制协议 优缺点
方案A DoIP的DiagnosticMessage UDS 0x34/0x36/0x37 兼容性好,但速度慢(单包最大4KB)
方案B SOME/IP的Method/Event 自定义传输协议 速度快,但需要额外开发

我个人更推荐方案B。为什么呢?

DoIP的DiagnosticMessage通道,本质上还是UDS的块传输。每个块最大4KB,还要等流控帧。传一个100MB的固件,光握手就要花掉不少时间。

而SOME/IP可以自己定义传输策略。比如,把固件切成1MB的块,用SOME/IP的Method批量发送。配合DoIP的TCP连接,速度能快好几倍。

// 伪代码示例:SOME/IP固件传输接口
method DownloadFirmware {
    // 输入:固件块数据 + 块序号
    input {
        uint32 block_id;
        uint8[] block_data;  // 最大1MB
        uint32 crc32;
    }
    // 输出:确认结果
    output {
        uint8 status;  // 0=成功, 1=重传
        uint32 next_block_id;
    }
}

避坑指南:我曾经遇到过一个项目,SOME/IP传输固件时,ECU的接收缓冲区太小,导致丢包。后来我们在SOME/IP的传输层加了滑动窗口机制,才解决问题。所以,设计传输协议时,一定要考虑ECU的内存限制。

阶段三:刷写与验证

固件传完了,接下来就是刷写和验证。这个阶段,DoIP又成了主角。

  • 刷写控制:通过DoIP的DiagnosticMessage发送UDS 0x31(例程控制),触发ECU内部的刷写流程
  • 安全验证:用DoIP的UDS 0x27(安全访问)做身份认证。嗯,这里要注意,安全访问的种子和密钥交换,必须在DoIP的TCP连接上进行,不能走SOME/IP
  • 状态上报:刷写进度、错误码等信息,通过SOME/IP的Event发布给OTA Master

你可能会问:为什么刷写控制不用SOME/IP?

因为刷写是诊断行为。UDS有完整的会话管理、安全等级、DTC处理机制。SOME/IP虽然也能做,但需要自己实现这些逻辑,太麻烦了。直接用DoIP+UDS,省心又标准。

4.3 协同工作的关键设计点

说几个我踩过的坑,你设计时一定要注意。

4.3.1 连接管理

DoIP和SOME/IP共用同一个TCP连接吗?

我的建议是:分开

DoIP用TCP端口13400,SOME/IP用TCP端口30490(或其他自定义端口)。这样互不干扰。如果共用一个连接,万一DoIP的诊断会话超时了,SOME/IP的通信也会受影响。

4.3.2 优先级与QoS

OTA升级时,网络带宽是有限的。控制指令(比如“停止升级”)必须优先于数据块传输。

我习惯的做法是:

  • DoIP的DiagnosticMessage通道,设置最高优先级
  • SOME/IP的Event(状态上报),设置中等优先级
  • SOME/IP的Method(固件传输),设置最低优先级

这样,即使固件传输占满了带宽,诊断指令也能及时送达。

4.3.3 超时与重试

OTA升级最怕什么?最怕“卡死”。

我曾经遇到过一个场景:固件传输到一半,ECU突然没响应了。DoIP的TCP连接还在,但SOME/IP的Method调用超时了。这时候,OTA Master该怎么做?

我的方案是:

  1. SOME/IP的Method超时后,先重试3次
  2. 如果还不行,通过DoIP发送UDS 0x22(读取数据)检查ECU状态
  3. 如果ECU状态异常,通过DoIP发送UDS 0x11(ECU复位)
  4. 复位后,重新开始SOME/IP的服务发现

说白了,就是让SOME/IP做“快速失败”,让DoIP做“兜底恢复”。

4.4 实战中的协同策略

最后,分享一个我实际用过的协同策略表。你可以直接参考。

场景 使用协议 具体操作 注意事项
车辆发现 DoIP UDP广播VIN请求 注意网络隔离,避免跨网段发现
服务发现 SOME/IP SD FindService/OfferService SD的TTL要匹配OTA升级时长
固件传输 SOME/IP Method 自定义块传输接口 加CRC校验,支持断点续传
刷写控制 DoIP + UDS 0x31例程控制 必须在扩展诊断会话下执行
状态上报 SOME/IP Event 周期性发布升级进度 频率不要太高,1秒1次足够
异常恢复 DoIP + UDS 0x11 ECU复位 复位后重新走服务发现流程

最后说一句:OTA升级的协同工作,没有银弹。每个项目的ECU资源、网络拓扑、安全要求都不一样。但记住一个原则:DoIP管“稳”,SOME/IP管“快”。把握好这个度,你的方案就不会跑偏。