拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

DoIP+UDS+OTA:车载以太网诊断协议栈与64MB固件升级实战拆解

DoIP+UDS+OTA:车载以太网诊断协议栈与64MB固件升级实战拆解 1. 项目概述为什么要把DoIP、UDS和OTA放在一起拆先说说背景。车载诊断这条线过去十几年基本被CAN总线统治OBD口出来一根CAN线连上诊断仪就能读故障码、读数据流、刷写ECU。但这两年情况明显变了智能座舱、辅助驾驶、域控制器这些上车之后单ECU的软件体量从几百KB直接涨到几十MB甚至上百MB一台车的控制器加起来固件包几百MB很常见。CAN总线最高也就1Mbps的带宽刷一个几十MB的包要几个小时工厂产线根本等不起售后OTA更是想都别想。所以DoIPDiagnostic over IP基于IP网络的诊断协议规范定义在ISO 13400就是在这个节骨眼上被大规模推向量产。这篇内容我打算用一台实际项目的网关设备做例子完整走一遍“UDS诊断 - 建立DoIP连接 - 64MB固件包OTA升级”的全流程把每一段报文都拆开来看。适合正在做车载以太网、UDS诊断栈、OTA刷写方案的朋友参考也适合刚转到汽车电子、想搞清楚DoIP到底和CAN诊断有什么区别的人。为什么要强调“64MB”因为这是当前OTA升级里一个很有代表性的分界点。小于2MB的固件传统CAN FD勉强能刷但体验已经很差到了64MB这个量级就必须用DoIP走以太网。我实测下来百兆车载以太网做64MB传输纯数据阶段大约5到6秒加上诊断流程和擦写时间整个升级事务控制在3分钟以内是可行的。这个体验只有DoIP能给。这次抓包我用的是PC USB网卡直连车载以太网交换机镜像口Wireshark抓包中间串了一个自研的DoIP诊断模拟器做网关转发。下面所有报文分析全部来自这份抓包文件。2. DoIP协议核心拆解连接、路由与报文结构2.1 连接建立从物理层到TCP连接DoIP在OSI模型里位于传输层之上底层走TCP/IP所以DoIP的连接流程本质上和“设备上网”没什么区别。测试设备Tester要找到车辆侧的DoIP实体Vehicle Gateway第一步是IP地址获取。实车上一般通过DHCP拿地址诊断仪也可以配置静态IP。需要注意的是车载以太网和办公室以太网不一样很多ECU支持Auto IPIPv4LL当DHCP不可用时自动退到169.254.x.x网段。开发阶段我建议直接用静态IP少一层依赖排查问题也方便。拿到IP之后DoIP有两个关键端口13400/TCP用于控制类报文和诊断报文13400/UDP用于车辆发现和公告。TCP端口承载的是可靠传输的控制流程UDP端口则承担了“车辆在网络上广播自己”的角色也就是DoIP的车辆发现机制Vehicle Announcement。诊断仪上线后向组播地址发一条Vehicle Identification Request车端网关就会回Vehicle Identification Response里面带VIN、逻辑地址、EID实体标识、GID组标识这些硬件身份信息。这一段流程结束后Tester会向网关发起TCP连接。这里有个经验点DoIP的TCP连接不限制只能建一条但诊断会话资源是有限的。ISO 13400里定义了一个节点最多支持多少个并发TCP连接超过会被拒绝返回0x02的NACK码。我们遇到过一个奇怪问题Tester重连时端口还挂在TIME_WAIT状态网关侧没做SO_REUSEADDR导致bind失败诊断会话一直起不来。后来在网关侧加了TCP参数调整这个问题才消失。2.2 DoIP报文头8个字节定一生DoIP报文没有“像UDS那样复杂的寻址结构”它的协议层非常简洁核心就是8字节的通用报文头定义了版本号、报文类型、负载长度。我们抓到的第一条DoIP报文是这么一段00 02 00 00 00 00 00 03拆开看00 02协议版本号。ISO 13400-2:2012对应的版本值是0x020x03是2019版本。00 00报文类型。0x0000是Generic DoIP header NACK0x0001是Vehicle Identification Request等等这个是0x0000即通用NACK。00 00 00 03负载长度后面紧跟着3个字节的负载。DoIP报文类型有很多但日常开发中核心关注这几种0x0001/0x0002车辆识别请求/响应、0x0003/0x0004路由激活请求/响应、0x0005/0x0006诊断消息请求/响应、0x8001/0x8002车辆公告请求/响应、0x4001Alive Check Request和0x4002Alive Check Response。整理成速查表更直观报文类型值名称方向用途0x0000Generic DoIP header NACKTester-Vehicle/Vehicle-Tester协议头错误比如版本不支持、负载过长0x0001Vehicle Identification RequestTester-Vehicle单播/组播查询车辆身份信息0x0002Vehicle Identification ResponseVehicle-Tester返回VIN、逻辑地址、EID、GID0x0003Routing Activation RequestTester-Vehicle路由激活申请诊断通道0x0004Routing Activation ResponseVehicle-Tester返回激活状态0x10成功0x0005Diagnostic MessageTester-Vehicle负载为完整的UDS诊断报文0x0006Diagnostic Message ACK/NACKVehicle-Tester确认诊断消息是否被路由0x4001Alive Check RequestVehicle-Tester检测激活路由是否还存活0x4002Alive Check ResponseTester-Vehicle响应Alive Check2.3 路由激活拿到诊断通行证TCP连接建立后Tester想发UDS诊断消息必须先做路由激活。这一步相当于“登录网关”告诉网关“我要发诊断我的逻辑地址是0x0E80”网关校验通过后分配一个源地址后续的诊断报文就带着这个地址在DoIP层内网路由。我们抓包里的路由激活请求00 02 00 03 00 00 00 07 0E 80 00 00 00 00 00 00 00 00 00 00DoIP头版本0x02类型0x0003负载长度7。负载0E 80是Tester的逻辑地址后面的激活类型和保留位默认填0。响应报文00 02 00 04 00 00 00 0B 0E 80 00 00 00 00 00 10 00 00 00 00 00 00注意倒数第5个字节是0x10这个就是激活响应码表示Routing Activation成功。其它常见的激活失败码有0x00拒绝确认、0x01拒绝不支持的激活类型、0x02拒绝Tester地址与已激活路由冲突、0x03拒绝节点忙、0x04拒绝未知目标地址、0x05拒绝VIN不匹配、0x06拒绝EID不匹配等。如果激活失败了大概率是这几个问题之一Tester逻辑地址和别的设备冲突、网关同时在线连接数达到上限、VIN没烧录很多网关在没VIN时不允许激活诊断。2.4 诊断消息的DoIP封装与寻址路由激活完成之后DoIP层就进入“透传UDS”模式。诊断消息通过0x0005类型报文传输负载结构如下00 02 00 05 00 00 00 0B 0E 80 00 00 00 00 00 00 00 00 03 22 F1 90拆开看DoIP头类型0x0005负载长度0x0B11字节。前4个字节是源地址Source AddressTester逻辑地址0x0E80。中间4个字节是目标地址Target AddressECU逻辑地址0x0000网关自身或具体ECU地址。后面的字节是真正的UDS报文03 22 F1 90含义是UDS长度3字节SID0x22按标识符读取数据DID0xF190一个自定义软件版本标识符。这里有个特别需要注意的点DoIP封装UDS时UDS报文前面的那个长度字节比如这里的0x03是UDS消息自身长度不是DoIP负载长度。DoIP的payload length包含源地址、目标地址、UDS消息长度字节、UDS消息本身的总和。初学的人在这个地方特别容易算错。我们写测试脚本时用Python的struct打包时也踩过这个坑算错了Wireshark里直接标记为Malformed排查了半天才发现是长度写错了。UDS on DoIP的寻址方式有物理寻址和功能寻址两种。物理寻址就是一对一目标地址填具体ECU的逻辑地址比如0x1070功能寻址的目标地址是所有ECU共享的功能地址比如0x1A00网关会把这条诊断消息广播到网段内所有ECU。OTA刷写过程一般用物理寻址因为擦写动作必须精确到单个ECU不能多个ECU同时执行某些读取操作可以用功能寻址做“一次问多个ECU”的效率优化。3. UDS诊断协议栈OTA升级的“地基”操作拆解3.1 诊断会话切换先进入扩展会话UDSISO 14229定义了几种诊断会话最基础的是默认会话0x01但真正干活儿基本都要切到扩展会话0x03或编程会话0x02。编程会话限制访问防止行车过程中误刷软件扩展会话允许执行写入、例程控制等操作。OTA升级的第一步就是切换会话。抓包报文Tester - ECU: 02 10 03 ECU - Tester: 02 50 03请求02 10 03SID0x10DiagnosticSessionControl子功能0x03扩展会话。响应02 50 030x50是0x10 | 0x40的肯定响应意思是“会话已切换当前是扩展会话”。如果ECU拒绝切换会返回NRC否定响应码。常见的NRC里0x22条件不满足出现得最多——ECU当前车速不为0、电源模式不对、未解锁安全等级都会拒掉会话切换。我们实测遇到过一个案例某个ECU在整车CAN网络上收到持续的动力CAN报文判定车辆处于“行驶状态”直接拒绝进入编程会话。解决办法是在诊断仪侧模拟整车环境通过CANoe或网关把车速信号置0再发会话切换。3.2 安全访问解不开锁什么都做不了从扩展会话进入编程会话后UDS会要求安全访问SecurityAccessSID 0x27。这一步是OTA链路里最“敏感”也最容易出问题的地方。机理是Tester先发27 01请求种子SeedECU返回一段随机数Tester用这段随机数按厂商算法计算出密钥Key发27 02提交ECU校验通过后返回67 02之后一段时间内允许执行写入操作。抓到的典型报文序列Tester - ECU: 02 27 01 ECU - Tester: 04 67 01 1A B2 C3 D4 Tester - ECU: 06 27 02 A1 B2 C3 D4 E5 F6 ECU - Tester: 02 67 02注意几个点种子一般是4字节但有的ECU用8字节甚至更长完全看厂商的算法。安全访问有次数限制。ISO 14229定义尝试次数的上限是厂商自定义一般是3到5次。连续失败会锁定一段时间我们调试时曾经因为算法写错把ECU锁了10分钟非常痛苦。种子和密钥的计算算法一般由Tester端的dll提供OEM不会公开。如果你是自己做Tester得先和OEM确认这个算法。这里有很强的安全考量在里面——正是有0x27服务这道门槛OTA刷写才能防止“随便一个设备连上OBD口就篡改固件”。在网关层面DoIP路由激活之后还要再做一次安全访问等于双层锁。在实际攻击面分析中我们也验证过如果TP层没做重放攻击防护录一段合法会话的报文再回放有一定概率能绕过安全锁所以正规实现都要加时间戳、计数器防重放。3.3 读取数据升级前先确认版本和环境安全访问通过后标准流程是先读ECU当前软件版本号、硬件版本号、序列号、配置字这些关键标识。这既是做升级前“资格检查”也是防止刷错零件号的保险。这里用的是0x22服务ReadDataByIdentifier。Tester - ECU: 03 22 F1 90 ECU - Tester: 06 62 F1 90 01 02 03 040xF190这个DID是软件版本号返回的01 02 03 04转换成ASCII就是类似“V1.2.3.4”的版本字符串。实际工程中建议在升级前把以下DID都读一遍软件版本、硬件版本、序列号、供应商代码、Bootloader版本、ECU装配日期。这些信息在刷写失败做根因分析时特别有用能快速判断是软件包传错还是ECU硬件不支持。3.4 例程控制升级的“开关”和“保险丝”例程控制RoutineControlSID 0x31在OTA里承担了大量“不是传输数据但必须做的事”。典型场景是刷写前的“预编程”和刷写后的“后编程”预编程关闭DTC记录0x31 01 02 02、禁用通信、停掉应用层程序、做一个内存擦除前的准备。后编程重新启用DTC记录、复位ECU、检查软件完整性、验证应用激活。举个实际报文例子关闭DTC记录Tester - ECU: 05 31 01 02 02 ECU - Tester: 02 71 01意思是执行01例程ID为0x0202的“停止记录故障码”例程执行成功返回71 01。我们的抓包里还看到一个很有意思的例程擦除Flash前的“存储器检查”ECU收到后先做一遍Flash坏块扫描返回擦除所需预估时间以秒为单位Tester依据这个返回值动态计算刷写超时阈值。0x31服务的坑主要在于例程ID完全是厂商自定义的同一个APID在不同OEM平台里可能对应不同功能所以调试一定要拿OEM提供的诊断调查表Diagnostic Descriptor对照着来。在我过往的项目里因为例程ID理解错位导致的刷写失败占了OTA问题里相当的比例。3.5 写入数据与传输数据64MB怎么塞进诊断协议OTA的重头戏就是固件包的传输。UDS里有两套传输方式0x2EWriteDataByIdentifier适合小数据量比如写配置字0x34/0x36/0x37RequestDownload/TransferData/RequestTransferExit才是大文件传输的正路。抓包里可以看到完整的0x34 - 多个0x36 - 0x37序列Tester - ECU: 0B 34 00 44 00 00 00 00 04 00 00 00 ECU - Tester: 07 74 00 44 01 F4 01 00 00请求的含义SID0x34dataFormatIdentifier0x00不压缩不加密addressAndLengthFormatIdentifier0x44表示后面的地址占4字节、长度占4字节然后跟4字节的Flash起始地址和4字节的数据总长度0x04000000 64MB。响应的含义0x74是肯定响应maxNumberOfBlockLength0x01F4500字节表示“每个block最多传500字节”。这里我实测统计过64MB固件包如果blockLength设成500字节需要发送大约131072个0x36请求。假设每个block传输时间是0.5ms百兆网下纯链路时间只要0.04ms但ECU擦写Flash耗时是主要瓶颈总耗时也要65秒加上擦除和校验时间整体在一两分钟量级。如果想优化可以把maxNumberOfBlockLength增大到4KB或更大。但FLASH驱动的buffer size决定了实际能接受多大blockLength强行调大可能导致ECU内存溢出崩溃所以这个值不是越大越好得跟ECU开发对齐。0x36传输的报文Tester - ECU: 04 36 01 xx xx xx ECU - Tester: 03 76 01 xx xx请求SID0x36blockSequenceCounter0x01后面是最多500字节的数据块。响应SID0x76返回当前已成功接收的块序号。注意一个问题如果请求里的块序号突然跳变比如从0x01直接跳到0x05ECU会判定为传输错误返回NRC 0x73wrongBlockSequenceCounter整个下载流程中止。传输结束发0x37Tester - ECU: 01 37 ECU - Tester: 02 773.6 编程后处理复位、验证与再次连接0x37之后ECU拿到了完整的固件镜像但此时它还只是在RAM缓冲区或固定下载区里。接下来要执行真正的Flash写入——一般通过0x31调用“编程”例程来完成同时做完整性校验CRC/签名。校验通过后用0x11服务ECUReset复位ECUECU重新上电自检应用软件启动。Tester - ECU: 02 11 01 ECU - Tester: 02 51 01代码0x01是hardReset0x03是powerDown。执行复位后TCP连接会断开需要重新做DoIP的路由激活和UDS会话切换然后再次读取软件版本号确认升级后的版本信息正确。整个OTA流程到这一步才算闭环。4. 64MB OTA升级抓包实战现场报文时间线复盘4.1 抓包环境怎么搭如果你也想复现整个流程环境大概是这样的一个支持DoIP的以太网网关我们用的是自研的代码基于开源移植上面跑着UDS诊断栈。一个16端口车载以太网交换机网关和Tester PC都接在上面PC的网卡做端口镜像或者在交换机上做span port。Wireshark抓包过滤条件doip如果装了UDS解析插件Wireshark还能自动把doip的payload解析成SID和参数。实测有一个很实用的技巧在Tester PC上除了抓包还可以用tshark -i eth0 -f udp port 13400 or tcp port 13400做实时日志输出把报文直接滚到命令行终端里当成流水线日志看。调试的时候比打开Wireshark GUI方便很多尤其适合挂在后台跑一整晚的稳定性测试。4.2 全流程时间线与报文摘录下面这个时间线是从64MB OTA抓包文件里按时间戳整理出来的每个阶段都标了耗时。我们用的ECU Flash擦除大约耗时18秒数据块大小500字节00到结束总计152秒。阶段起始时间结束时间耗时关键报文DoIP连接与路由激活0.000s0.142s142ms0x0003路由激活读取软件版本0.152s0.214s62ms22 F1 90 读版本切换编程会话0.226s0.261s35ms10 02 切编程会话安全访问0.290s0.425s135ms27 01/27 02预编程例程0.442s1.253s811ms31 01 02 02Flash擦除1.280s19.865s18.585s31 01 FF 00请求下载19.902s19.945s43ms34 00 44 …传输64MB数据19.962s91.337s71.375s0x36 x 130k次请求传输退出91.354s91.386s32ms37编程校验91.400s142.110s50.710s31 01 02 01复位142.133s142.152s19ms11 01重新连接DoIP143.360s143.522s162ms路由激活读版本确认143.533s143.596s63ms22 F1 90这份抓包里我发现两个非常有意思的点。第一Flash擦除花了18.6秒但这段过程里Tester几乎“无事可做”只能等。很多DoIP实现会把擦除动作和“RoutineControl”合并成一条长超时请求Tester的超时时间必须设得够长我们设的是30秒否则Tester会先报超时然后ECU过一会再回响应时序就乱了。第二64MB数据传输本身只要71秒平均吞吐量约0.9MB/s并没有跑到百兆网络的极限。瓶颈在ECU侧接收Flash写入的速率链路带宽根本不是问题。这也解释了为什么DoIP方案能撑起更大体量的OTA——瓶颈在ECU端的存储写入而不在协议本身。4.3 Wireshark过滤规则与高效分析技巧抓包文件动辄几十万条报文靠肉眼翻肯定不行。我整理了几条最实用的过滤规则只看DoIP协议doip只看路由激活相关doip.msg_type 0x0003 || doip.msg_type 0x0004只看诊断消息0x0005doip.msg_type 0x0005只看UDS肯定响应doip.msg_type 0x0005 uds.sid 0x50 uds.sid ! 0x7F当Wireshark启用了UDS解析时只看NRC否定响应uds.nrc ! 0x00只看特定源地址的请求doip.src_address 0x0e80统计每个DoIP报文类型的数量doip.msg_type还有一个很推荐的功能Wireshark的“Telephony - VoIP Calls”不适用但“Statistics - IO Graph”很好用把过滤器设成doip.msg_type 0x0005 uds.sid 0x36就能画出一根“0x36传输带宽随时间变化”的曲线。如果看到曲线中间有塌陷或者停止说明传输过程中出现了等待或重传可以顺藤摸瓜找到瓶颈。我们之前定位一个“OTA卡在50%不动”的bug就是用IO Graph发现0x36的速率突然掉到接近0再对照时间戳看到TCP层发生了大量重传最后定位到是车载交换机端口协商成了半双工模式导致丢包。5. 常见问题与排障实录踩过的坑都在这里5.1 UDS常见否定响应码速查OTA调试中NRC是最高频的“对话内容”很多问题其实是一眼就能看出来的。我把最常见的NRC整理成了表NRC (Hex)名称含义常见原因0x10General Reject一般拒绝请求格式不对、服务不支持0x11Service Not Supported服务不支持SID拼写错误或该ECU未实现此服务0x12Sub-Function Not Supported子功能不支持例如0x10服务里子功能0x04不存在0x13Incorrect Message Length Or Invalid Format报文长度错误请求少了参数或多填了字节长度字段算错0x22Conditions Not Correct条件不满足会话不对、车速不为0、未解锁、电源模式不对0x31Request Out Of Range请求超出范围DID/例程ID不存在、Flash地址越界0x33Security Access Denied安全访问被拒绝种子/密钥错误、访问次数超限0x35Invalid Key密钥无效密钥算错或算法不一致0x36Exceed Number Of Attempts尝试次数超限安全访问连续失败被锁定0x72General Programming Failure编程失败Flash写入失败、校验失败0x73Wrong Block Sequence Counter块序号错误0x36序号跳变0x78Request Correctly Received, Response Pending响应待处理ECU正在忙需要Tester继续等待0x78这个响应特别常见也特别容易被误解。ECU处理长任务时会先回一个0x78表示“我已经收到了但还没干完你继续等”。Tester收到0x78之后必须保持当前请求的上下文不能发新请求直到ECU发来最终响应。有些自研Tester没有实现0x78的循环处理逻辑导致刷写流程直接崩掉这是初学者必踩的坑。5.2 DoIP连接与传输层疑难杂症DoIP本质上是TCP/IP上的应用协议所以经典的网络问题它一个不落都会遇到。我列几个亲身踩过的高频问题路由激活失败返回0x02Tester地址冲突多台Tester同时连到同一个网关且共用了相同的逻辑地址。生产环境里多台诊断仪的地址配置需要统一规划不能随便填0x0E80。诊断请求发出去了ECU没任何响应先用Wireshark在Tester侧看报文有没有发到网卡上再看网关侧日志确认有没有收到再在ECU侧抓一次确认ECU有没有回。逐段断开排查基本能定位。我们遇到过一例ECU的UDS接收线程死锁TCP连接还活着但应用层就是不响应。TCP粘包/拆包导致DoIP报文被截断DoIP报文头8字节里的payload length字段是唯一的拆分依据实现时必须按“读够8字节头 - 解析payload length - 再读够payload length”的方式循环读取。很多初学协议栈的人直接用recv一次读固定长度遇到大包被TCP拆成多段就解析失败了。解决方案是维护一个接收缓冲区和状态机。64MB传输约5分钟后TCP连接被断开我们在测试中发现有的ECU TCP keep-alive机制没实现好长时间大流量传输后连接被中间设备认为空闲而杀掉。解决办法是应用层定期发Alive Check Request或者干脆在ECU侧把TCP keepalive参数调短。OTA过程中出现0x33安全访问拒绝但明明密钥是对的ECU内部的安全访问“已解锁状态”是有超时的通常在几秒到几十秒内有效。如果前面读版本号、切会话花的时间太长解锁状态已经过期了。刷写脚本里要把“安全访问”放在真正写入Flash的紧前面中间不要插入耗时长的大流量操作。5.3 安全性探讨OTA链路面临的实际威胁与防御既然热词里有“威胁及防御”这块我也说几句实操层面的体会。DoIP OTA的最大暴露面在于只要拿到了车载以太网的物理访问权比如OBD口、服务接口、甚至被攻破的车机做跳板任何人都可以尝试对ECU做路由激活、UDS诊断和固件刷写。具体威胁有这几类未授权诊断直接连上DoIP端口用标准UDS服务读取车内数据。防御手段是路由激活环节加认证比如要求Tester提供证书或预共享密钥网关校验通过后才允许激活。重放攻击录一段合法的诊断会话报文原封不动地重放。如果ECU没做时间戳、随机数、序列号绑定重放有可能绕过安全访问。防御方式是安全访问的种子要带随机性并且对每次请求做防重放校验。DoS攻击向网关发起大量TCP连接或大量诊断请求耗尽会话资源。ISO 13400里定义的并发连接上限就是一道防线网关侧还需要做IP白名单、速率限制、会话超时回收。我们实测用脚本每秒发200次路由激活请求不做限流的网关很快就无法响应正常诊断了。固件包篡改OTA升级包在传输过程中被篡改或者被替换成恶意固件。防御手段是固件包做数字签名RSA/ECDSA和完整性校验CRC/SHA256ECU写入前必须验证签名。这一点在我们做的安全测评里是强制项没有签名验证的OTA链路基本可以直接判不合格。给正在做DoIP/OTA开发的人一句实在话DoIP带来的便利是双向的能让你快速刷写也能让别人快速攻击。不要把安全只当成“上线前加个证书”要从架构层面把“身份认证、权限分级、防重放、完整性校验”嵌入到整个诊断会话生命周期里。6. 我的实操心得与后续扩展方向项目做下来一个深刻的感受是DoIP本身不难真正难的是UDS状态机和多ECU协同的复杂性。如果你是从CAN诊断转过来你会发现DoIP的报文结构比CAN诊断简单太多——没有CAN ID的P2/P3仲裁没有复杂的多帧传输层协议一切都有清晰的IP和TCP语义。但恰恰因为太“简单”隐藏了很多需要自己处理的细节TCP连接管理、粘包处理、长超时场景、多客户端并发、会话资源回收等等。后续扩展方向我觉得有几个很值得做把检测脚本自动化上面所有报文分析流程可以封装成Python脚本基于python-can/scapy或自研的DoIP库实现自动化OAT升级回归测试每晚跑一轮输出测试报告。引入ISO 13400-2:2019的新特性2019版本增加了一些安全和扩展相关的内容自动化测试和工具链需要跟上新版本。做UDS协议栈源码级别的裁剪与优化我们用的自研栈在收到大量0x36时CPU占用偏高后来做了批量接收重排、队列深度限制、Flash写入异步化才把刷写吞吐拉上去。尝试不依赖OEM的刷写链路线如果你也想自己搭一套完整的DoIP刷写工具链建议从Wireshark抓包分析开始然后基于开源的DoIP协议栈做一个Tester脚本在仿真环境里反复验证每个SID的时序关系踩过一轮坑之后再做量产方案成功率会高很多。最后分享一个其实很小但救过我好几次的习惯每次抓包前先把Tester、网关、ECU的时间基准先对齐NTP或者手动设定并且在Tester侧记录本机日志。这样万一OTA出问题我能把Wireshark的时间戳、Tester日志、ECU日志三条时间线拉到一起做交叉分析定位效率翻倍。现在每次做OTA项目我都会先花十分钟把这个基础打牢后面能省出好几个小时的排障时间。
返回列表