新能源汽车普遍具备OTA升级的功能。
而ECU往往是通过CAN通信接受升级的数据包并完成更新升级。
本篇文章分析新能源汽车OTA升级中的UDS通信。
OTA升级时UDS通信的双方是Tester和ECU。
OTA升级前,汽车车机需要从远程的服务器上下载到升级安装包,并利用签名算法验证升级安装包的完整性。
每次OTA升级大概要花费1个小时的时间。
因此,汽车OTA包下载到本地后车机后,车机和ECU通信前,需要检查汽车是否具备OTA升级的条件。
比如:汽车的电量是否够?汽车是否是停车状态?
如果汽车升级环境不具备,则禁止升级。
每次OTA升级,会涉及多个ECU,他们之间有时有顺序关系,但是对于每个ECU的升级步骤则大同小异,这里针对单个ECU的升级过程做分析。这里拿canid是“710/718”的ECU举例。
UDS报文data的格式为:
单帧:正文长度 + UDS服务编号 + 填充符
多帧:较为复杂,见具体解释。
再次确认汽车升级环境具备了。
大多数情况下,这一步可以忽略。
对于部分使用频率不高的ECU,可能大多数时间处于休眠状态,如果汽车内部通信畅通,ECU在汽车正常工作状态时会受到汽车某其他ECU发过来的请求唤醒的报文。ECU在被唤醒后才可以进行OTA升级。
tester向ECU发送
canid:0x710
data: [0x02, 0x10, 0x03, 0x55, 0x55, 0x55, 0x55, 0x55]
ECU回复tester
canid:0x718
data: [0x06, 0x50, 0x03, 0x00, 0x32, 0x01, 0xf4, 0xaa]
报文内容解读:
0x32, 0x01, 0xf4:
0x0032=50ms=0.05秒: p2server_max,指的是ECU在收到请求和给出响应之间的这个时间间隔,他描述了ECU的反应速度。
0x01f4=0x01F4*10ms=5000ms=5秒: p2*server_max。
诊断仪收到这两个参数之后,就对ECU的响应速度有了认知,可以据此来判断ECU的响应是否及时。
推荐阅读资料:
统一诊断服务(UDS) - 诊断会话控制(Diagnostic Session Control)_百战穿甲的博客-CSDN博客_uds会话
tester向ECU发送
canid:0x710
data: [0x04, 0x31, 0x01, 0x02, 0x03, 0x55, 0x55, 0x55]
ECU回复tester
canid:0x718
data: [0x04, 0x71, 0x01, 0x02, 0x03, 0xaa, 0xaa, 0xaa]
推荐阅读资料:
UDS 服务 Service 0x31 - RoutineControl_aFakeProgramer的博客-CSDN博客_uds31服务
tester向ECU发送广播
canid:0x7DF
data: [0x02, 0x85, 0x02, 0x55, 0x55, 0x55, 0x55, 0x55]
tester向ECU发送广播
canid:0x7DF
data: [0x03, 0x28, 0x03, 0x01, 0x55, 0x55, 0x55, 0x55]
推荐阅读资料:
UDS服务基础篇之85服务 - 知乎
UDS(七)应用层 28/85_车小猿的博客-CSDN博客_uds85服务
要想具有刷写ECU的权限,必须顺利进入02编程会话,而能否顺利进入02编程会话的前提则是安全解锁验证要能通过。
tester向ECU请求seed
canid:0x710
data: [0x02, 0x27, 0x01, 0x55, 0x55, 0x55, 0x55, 0x55]
ECU回复tester seed
若seed长度为2个字节:
canid:0x718
data: [0x04, 0x67, 0x01, key0, key1, 0xaa, 0xaa, 0xaa]
若seed长度为4个字节:
canid:0x718
data: [0x06, 0x67, 0x01, key0, key1, key2, kehy3, 0xaa]
tester向ECU发送key请求鉴权
若seed长度为2个字节:
canid:0x710
data:[0x06, 0x27, 0x02, key0, key1, 0x55, 0x55, 0x55]
若seed长度为4个字节:
canid:0x710
data:[0x06, 0x27, 0x04, key0, key1, key2, key3, 0x55]
ECU回复tester鉴权通过
canid:0x718
data: [0x02, 0x67, 0x02, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa]
tester向ECU发送
canid:0x710
data:[0x02, 0x10, 0x02, 0x55, 0x55, 0x55, 0x55, 0x55]
ECU回复tester
canid:0x718
data: [0x06, 0x50, 0x02, 0x00, 0x32, 0x01, 0xf4, 0xaa]
推荐阅读资料:
UDS之浅谈27服务_涓涓悦然的博客-CSDN博客
tester向ECU发送请求下载第1帧
canid:0x710
data:[0x10, 0x0b, 0x34, 0x00, 0x44, 0xfe, 0xf2, 0x70]
ECU回复tester 流控帧
canid:0x718
data:[0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
tester向ECU发送请求下载第2帧
canid:0x710
data:[0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x55, 0x55]
ECU回复tester正面响应
canid:0x718
data:[0x04, 0x74, 0x20, 0x0f, 0xf2, 0xaa, 0xaa, 0xaa]
报文内容解读:
Tester向ECU请求下载报文长度超过一个标准帧,所以被拆成第1帧和第2帧,以多帧的形式发送。
0x10, 0x0b,:1表示多帧的首帧,00b表示报文正文长度。
0x34, 0x00, 0x44: 表示34下载服务
0xfe, 0xf2, 0x70, 0x00, 0x00, 0x00, 0x01, 0x00:
表示 startAddress(0xfef27000)+blockSize(00001000)
0x21:表示多帧的第二帧
ECU在接收到多帧的首帧后,会向Tester主动发一条流控帧
流控帧0x3后面的含义:第一位0x00,流控状态,这里假设其值为0,表示续帧可持续发送 第二位0x00,表示只发一帧流控帧,服务端将一直发续帧直到全部数据发送完毕,第三位表示续帧发送的最小时间间隔多长(0x00,0ms)
Tester在收到流控帧后才发多帧的第2帧。
0x20, 0x0f, 0xf2:
这里 0x20(length of format identifier) 0x0ff2(maxnumber of block length)
推荐阅读资料:
UDS诊断之34服务 - 知乎
UDS(十)应用层 34/36/37_车小猿的博客-CSDN博客_34服务
tester向ECU发送请求文件传输
canid:0x710
data:[ 0x13,0xD4,0x36,0x01,0x1E,0xEF,0x20,0xA0]
ECU回复tester流控帧
canid:0x718
data:[0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
tester向ECU继续发送续帧
canid:0x710
data:[ 0x21,0x14,0x00,0xE0,0x00,0x66,0x00,0xE0]
当续帧全部发送完成后,ECU给tester发送回复
canid:0x718
data:[0x02, 0x76, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00]
若tester发现flash已经全部发送成功,则向ECU发送请求退出传输:
canid:0x710
data:[0x01, 0x37, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55]
ECU回复tester请求退出传输的正面响应
canid:0x718
data:[0x01, 0x77, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa]
本节发送的报文结构比较复杂,且报文组包和上一节的ECU回复有强关联,具体组包原则可以查看
根据hex文件制作UDS统一诊断服务CAN多帧报文-python_晓翔仔的博客-CSDN博客_uds多帧发送
tester向ECU发送请求CRC32验证,报文包含了CRC32正确值(0x63F4DF27)
canid:0x710
data:[0x10, 0x08, 0x31, 0x01, 0x02, 0x02, 0x63, 0xF4]
ECU回复tester流控帧
canid:0x718
data:[0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
tester向ECU继续发送续帧
canid:0x710
data:[0x21, 0xDF, 0x27, 0x55, 0x55, 0x55, 0x55, 0x55]
ECU验证CRC32是正确的,向tester发送CRC32验证通过的正面响应
canid:0x718
data:[0x05, 0x71, 0x02, 0x02, 0x02, 0xaa, 0xaa, 0xaa]
关于CRC32的计算可以查看
用python计算Intel Hex文件数据的checksum“CRC32”的值_晓翔仔的博客-CSDN博客
tester向ECU发送请求擦除即将要刷写的空间地址范围,报文包含了请求擦除的起始地址和地址长度(0x00c10000+0x00038000)
canid:0x710
data:[0x10, 0x0d, 0x31, 0x01, 0xff, 0x00, 0x44, 0x00]
ECU回复tester流控帧
canid:0x718
data:[0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
tester向ECU继续发送续帧
canid:0x710
data:[0x21, 0xc1, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00]
ECU擦除成功,向tester发送擦除结果的正面响应
canid:0x718
data:[0x05, 0x71, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00]
同3.6节
同3.7节
同3.8节
tester向ECU发送请求获取版本号
canid:0x710
data:[0x03, 0x22, 0xF1, 0x8C, 0x55, 0x55, 0x55, 0x55]
ECU获取版本号并回复报文1
canid:0x718
data:[0x0c, 0x62, 0xF1, 0x8C, 0x31 0x32, 0x33, 0x34]
tester向ECU发送请求流控帧
canid:0x710
data:[0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
继续发送版本号的报文2
canid:0x718
data:[0x21, 0x35, 0x36, 0x37, 0x38 0x39, 0xaa, 0xaa]
例子里报文携带的版本号是“123456789”。
推荐阅读资料:
UDS服务基础篇之22_汽车小T的博客-CSDN博客_22服务 uds
tester向ECU发送请求重启
canid:0x710
data:[0x02, 0x11, 0x01, 0x55, 0x55, 0x55, 0x55, 0x55]
ECU重启并回复
canid:0x718
data:[0x02, 0x51, 0x01, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa]
推荐阅读资料:
UDS诊断服务基础篇之11 - 知乎
tester向ECU发送广播
canid:0x7DF
data: [0x02, 0x85, 0x01, 0x55, 0x55, 0x55, 0x55, 0x55]
tester向ECU发送广播
canid:0x7DF
data: [0x03, 0x28, 0x03, 0x01, 0x55, 0x55, 0x55, 0x55]
推荐阅读资料:
UDS服务基础篇之85服务 - 知乎
UDS(七)应用层 28/85_车小猿的博客-CSDN博客_uds85服务
至此,OTA升级的UDS报文过程交换全部结束。
若ECU处理消息比较慢,有时会主动发送一个消息挂起的回复
canid:0x718
data:[0x03, 0x7f, serviceid, 0x78, 0xaa, 0xaa, 0xaa, 0xaa]
ECU返回NRC 0X78,说明ECU当前处理能量不足,所以需要更长的反应时间。这是tester需要再等一等,不要轻易判定ECU已经拒绝回复了。
在进入特殊会话模式后,一般5秒内没有数据传输,就会退回默认会话。
tester往往会每隔2-4秒发一个握手报文,来维持会话。
如果握手报文格式如:
canid:0x710
data:[0x02, 0x3E, 0X80, 0x55, 0x55, 0x55, 0x55, 0x55]
则无肯定响应报文回复
如果握手报文格式如:
canid:0x710
data:[0x02, 0x3E, 0X00, 0x55, 0x55, 0x55, 0x55, 0x55]
则有肯定响应报文回复
canid:0x718
data:[0x02, 0x7E, 0X00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa]
推荐阅读资料:
UDS诊断之3E服务 - 知乎
本文主要分析了一次OTA升级步骤里用到的UDS服务以及报文解释。
饭饭是我的朋友,他对UDS服务也有一定研究,他的这篇文章很清晰了讲述了他对UDS刷写安全的理解。
青骥原创 l 车联网安全基础知识之 UDS 刷写安全
UDS服务的种类不是特别多,响应的格式也有规范的说法。
可以查阅了解所有类型UDS服务。
统一诊断服务(UDS)_晓翔仔的博客-CSDN博客_uds 库