3、DoIP消息结构:通用DoIP消息头、Payload类型与编码、消息格式实例分析

好,咱们今天聊聊DoIP的消息结构。说实话,这是整个DoIP诊断的基础。你想想看,车上的ECU和诊断仪之间怎么说话?总得有个规矩吧。这个规矩就是消息结构。

我刚开始接触DoIP的时候,也犯过迷糊。看着那一串十六进制数,完全不知道谁是谁。后来做项目多了,慢慢就摸清了门道。今天我把这些经验掰开了揉碎了讲给你听。

3.1 通用DoIP消息头

每个DoIP消息,开头都是一样的。这个开头就是通用消息头。它就像信封上的地址,告诉接收方这封信该怎么处理。

消息头固定8个字节,不多不少。结构如下:

字段 长度(字节) 说明
协议版本号 1 当前固定为0x02(ISO 13400-2:2012)
逆协议版本号 1 取反,0xFD
Payload类型 2 标识消息的具体用途
Payload长度 4 后续数据的字节数,大端序

嗯,这里要注意。协议版本号0x02是目前最常用的。有些老设备可能用0x01,但我在项目中基本没见过。如果你遇到版本不匹配,连接会直接断开。我曾经在测试一台国产ECU时,它居然返回了0x03,搞得我排查了半天。后来发现是固件bug。

Payload类型是个关键字段。它决定了消息体里装的是什么。后面我会详细讲。

Payload长度是4字节,最大能表示4GB的数据。但实际中,诊断消息一般也就几百字节。你想想看,谁会在车上传输大文件?

3.2 Payload类型与编码

Payload类型用两个字节表示。ISO 13400-2里定义了很多类型。我挑几个最常用的给你说说。

类型值(十六进制) 名称 方向
0x0001 Generic DoIP header negative acknowledge 双向
0x0002 Vehicle Identification Request 诊断仪→ECU
0x0004 Vehicle Identification Request with EID 诊断仪→ECU
0x0005 Vehicle Identification Request with VIN 诊断仪→ECU
0x0006 Vehicle Announcement/Vehicle Identification Response ECU→诊断仪
0x0007 Routing Activation Request 诊断仪→ECU
0x0008 Routing Activation Response ECU→诊断仪
0x8001 Diagnostic Message 双向

我个人习惯把类型分成三类:

  • 发现类:0x0002、0x0004、0x0005、0x0006。用于找车、认车。
  • 连接类:0x0007、0x0008。用于建立诊断会话。
  • 诊断类:0x8001。真正干活的消息。

编码方式很简单。所有多字节字段都是大端序。也就是高位在前,低位在后。比如Payload长度是0x00000100,那就是256字节。

重要提醒:诊断消息(0x8001)的Payload里,前两个字节是目标地址,后两个字节是源地址。然后才是真正的UDS诊断数据。这个结构很多人会搞错。

3.3 消息格式实例分析

光说不练假把式。咱们直接看几个实际报文。

实例1:车辆识别请求

诊断仪发送:

02 FD 00 02 00 00 00 00

拆开看:

  • 02:协议版本
  • FD:逆版本
  • 00 02:Payload类型,车辆识别请求
  • 00 00 00 00:Payload长度,0字节

这个请求不需要额外数据。ECU收到后,如果支持,就会回复车辆公告消息。

实例2:路由激活请求

诊断仪发送:

02 FD 00 07 00 00 00 07
0E 10 00 00 00 00 00

消息头之后还有7个字节:

  • 0E:激活类型,0x0E表示默认激活
  • 10:保留字节
  • 00 00 00 00:源地址,这里是0
  • 00:保留字节

我记得第一次写路由激活代码时,源地址填错了。结果ECU一直返回否定响应。排查了半天才发现是地址写反了。你想想看,这种低级错误多耽误事。

实例3:诊断消息(读取数据)

假设我们要读取ECU的VIN码,UDS服务是0x22,DID是0xF190。

诊断仪发送:

02 FD 80 01 00 00 00 05
0E 00 00 00 22 F1 90

解析:

  • 消息头:类型0x8001,长度5字节
  • 0E 00:目标地址(0x0E00,通常是网关地址)
  • 00 00:源地址(0x0000,诊断仪自己)
  • 22 F1 90:UDS请求,读取DID F190

我的经验:地址分配在项目中很容易乱。我建议你一开始就画好地址映射表。哪个ECU用哪个逻辑地址,写清楚。不然调试时你会疯掉。

实例4:诊断响应

ECU回复:

02 FD 80 01 00 00 00 14
00 00 0E 00 62 F1 90 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00

这里:

  • 目标地址变成了0x0000(诊断仪)
  • 源地址是0x0E00(ECU)
  • 0x62是UDS响应,对应0x22服务
  • 后面跟着17字节的VIN数据(这里用0填充了)

嗯,这里要注意。诊断响应里的地址是反过来的。发送时目标地址是ECU,响应时目标地址就是诊断仪。这个逻辑很自然,但新手容易晕。

3.4 避坑指南

做DoIP消息解析,有几个坑我踩过:

  • 长度字段别算错:Payload长度不包括消息头本身。我见过有人把8字节头也算进去,结果ECU直接丢弃。
  • 大端序别搞反:有些嵌入式平台默认是小端。如果你不做转换,解析出来的长度就是错的。
  • 诊断消息的地址别漏:0x8001类型的Payload里,前4字节是地址。很多人直接塞UDS数据,忘了加地址。ECU收到后一脸懵。

曾经有一次,我在测试一个OEM的DoIP实现。他们的ECU对消息头校验特别严格。协议版本号必须是0x02,逆版本必须是0xFD。我试过用0x01发请求,ECU直接回了0x0001类型的否定响应。所以,别想着偷懒。

好了,DoIP消息结构就讲到这里。说白了就是8字节头加上可变长度的Payload。你只要记住类型和编码规则,解析起来就不难。下一章咱们聊聊路由激活的具体流程,那个更有意思。