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。你只要记住类型和编码规则,解析起来就不难。下一章咱们聊聊路由激活的具体流程,那个更有意思。