2. 车载诊断基础
好,咱们今天聊聊DoIP的协议栈。说白了,它就是一套让诊断数据能在以太网上跑起来的规矩。我刚开始接触DoIP的时候,第一反应是——这不就是把CAN诊断报文塞进以太网包里吗?后来踩了几个坑才明白,事情没那么简单。
DoIP协议栈参考了OSI七层模型,但实际落地时,我们主要关注五层:物理层、传输层、网络层、会话层和应用层。每一层各司其职,少了哪一层,诊断都跑不顺。
核心观点:DoIP不是简单地把UDS报文封装进TCP/UDP,它在每一层都做了针对车载环境的特殊设计。不理解这些设计,你写出来的诊断工具大概率会跟ECU“鸡同鸭讲”。
2.1 物理层——车上的“网线”长什么样
物理层是协议栈的基石。DoIP的物理层用的是车载以太网,不是咱们办公室里的那种RJ45网口。车上用的是100BASE-T1或1000BASE-T1,一对差分线搞定收发。
我记得第一次在台架上调试DoIP,拿了一根普通网线插上去,ECU死活不通。后来才发现,车载以太网的物理层用了不同的编码方式和共模电压。嗯,这个坑我替你们踩过了。
| 特性 | 100BASE-T1 | 标准以太网(100BASE-TX) |
|---|---|---|
| 线对数量 | 1对差分线 | 2对差分线 |
| 连接器 | 专用车载连接器 | RJ45 |
| 共模电压 | 1.5V ~ 2.5V | 0V |
| 主要应用 | 车载诊断、音视频 | 办公网络 |
实战建议:做DoIP测试时,务必确认物理层是100BASE-T1还是1000BASE-T1。两者不兼容,插错了没反应。我习惯在测试前先用示波器看差分信号幅值,确认物理层在正常工作。
2.2 网络层——给ECU发个“门牌号”
网络层负责寻址和路由。DoIP强制要求支持IPv6,同时兼容IPv4。为什么用IPv6?你想想看,一辆车上几十个ECU,未来还有V2X,IPv4的地址空间根本不够用。
每个支持DoIP的ECU都有一个逻辑地址(Logical Address),比如0x0E80代表网关,0x1001代表发动机ECU。诊断仪发请求时,网络层会把逻辑地址映射到IP地址上。
注意:DoIP的“车辆发现”功能依赖网络层的广播/组播机制。诊断仪通过UDP广播发送车辆识别请求(VIN),ECU回复自己的IP和逻辑地址。如果网络层配置不对,诊断仪可能连车都“找”不到。
2.3 传输层——TCP还是UDP?看场景
传输层是DoIP的“交通调度员”。它用了两种协议:
- TCP(端口13400):用于诊断消息的可靠传输。说白了,诊断请求和响应必须一个不丢、顺序不乱,所以用TCP。
- UDP(端口13400):用于车辆发现和诊断连接状态通告。这些消息不需要确认,丢了可以重发,UDP更高效。
我遇到过一个问题:诊断仪发了一个路由激活请求,ECU没回。查了半天,发现是TCP连接被中间设备重置了。后来我在代码里加了TCP keep-alive,问题就解决了。
2.4 会话层——握个手,建立连接
会话层是DoIP协议栈里最“有存在感”的一层。它负责:
- 路由激活(Routing Activation):诊断仪发一个激活请求,ECU验证后建立诊断路由。
- 诊断连接管理:每个诊断会话都有一个唯一的连接ID,防止多个诊断仪冲突。
- 保活机制(Alive Check):定期发送保活消息,检测连接是否还活着。
说白了,会话层就是诊断仪和ECU之间的“握手”和“心跳”。没有会话层,你连诊断通道都打不开。
避坑指南:我曾经在实车测试时,诊断仪连上后几分钟就断开了。查日志发现是ECU的保活定时器设得太短,诊断仪没来得及回复。后来我把保活间隔统一设为5秒,两边对齐,问题解决。
2.5 应用层——UDS诊断报文在这里
应用层是咱们最熟悉的一层。它承载了UDS诊断服务,比如读取故障码(0x19)、读取数据(0x22)、写入数据(0x2E)等。DoIP的应用层在UDS报文外面包了一层DoIP头部,用来标识消息类型和长度。
一个典型的DoIP诊断请求长这样:
| DoIP头部 (8字节) | UDS请求 (N字节) |
| 协议版本 | 消息类型 | 负载长度 | 用户数据 |
举个例子,读取VIN的UDS请求(0x22 0xF1 0x90),在DoIP里会变成:
02 FD 80 00 00 00 00 03 22 F1 90
|-- DoIP头部 --| |-- UDS --|
其中02 FD是协议版本和消息类型,80 00是连接ID,00 00 00 03表示后面UDS数据有3个字节。
小技巧:调试DoIP应用层时,我习惯先用Wireshark抓包,过滤条件设为tcp.port == 13400。这样能清晰看到DoIP头部和UDS报文的对应关系,排查问题特别快。
2.6 五层协作——一个诊断请求的完整旅程
咱们用一个实际场景串一遍:诊断仪想读取发动机ECU的故障码数量。
| 层级 | 做的事情 |
|---|---|
| 应用层 | 构造UDS请求:0x19 0x01(读取故障码数量) |
| 会话层 | 检查诊断连接是否激活,分配连接ID |
| 传输层 | 将数据通过TCP连接发送到ECU的13400端口 |
| 网络层 | 根据ECU的逻辑地址,找到对应的IPv6地址,封装IP包 |
| 物理层 | 将数字信号转换成差分信号,在100BASE-T1线对上传输 |
ECU收到后,按相反顺序逐层解包,最终把UDS请求交给诊断应用处理。整个过程,从诊断仪按下“读取”按钮到ECU响应,通常不超过50毫秒。
性能提醒:如果某层处理慢了,整个诊断链路都会变慢。我见过一个案例,ECU的TCP窗口设置太小,导致诊断响应被分成了好几个包,应用层等了很久才拼完整。调大TCP窗口后,响应时间从200ms降到了30ms。
好了,DoIP协议栈的五层架构就聊到这儿。每一层都有它的设计逻辑和坑点,理解了这些,后面咱们讲具体实现时,你就能更快上手了。