2. 诊断会话控制(0x10):会话切换失败排查、默认/扩展/编程会话的权限管理、超时机制

大家好,我是你们的讲师。今天我们来聊聊诊断会话控制,也就是0x10服务。这个服务在UDS开发里,可以说是最基础、也最容易出幺蛾子的地方。很多刚入行的朋友,甚至一些老手,都在这上面栽过跟头。我自己就见过不少因为会话切换失败,导致后续诊断流程全部卡死的案例。

说白了,0x10服务就是告诉ECU:“嘿,我要开始干活了,你准备好没?” 但ECU可不是随便就能切换状态的,它有自己的“脾气”和“规矩”。我们今天就把它彻底捋清楚。

2.1 会话切换失败排查:问题到底出在哪?

会话切换失败,是0x10服务最常见的故障现象。你发个10 02想切到编程会话,结果ECU回了个7F 10 12(子功能不支持)或者7F 10 22(条件不满足)。这时候怎么办?

我个人习惯,先看否定响应码(NRC)。不同的NRC,指向的问题完全不同。

  • NRC 0x12(子功能不支持):这通常意味着ECU压根不认识你请求的这个会话。比如你发10 04,但ECU只支持默认(01)、扩展(02)和编程(03)会话。那04是什么?ECU一脸懵。检查一下你的诊断描述文件(CDD/ODX),看看支持的会话列表。
  • NRC 0x22(条件不满足):这是个大坑。ECU告诉你:“我知道你想切,但现在不行。” 原因可能有一大堆。比如,你正在刷写程序,ECU不允许你切回默认会话;或者你之前没做安全解锁,就想切到编程会话。我在项目中遇到过,一个同事调了三天没搞定,最后发现是ECU要求切到编程会话前,必须先进入扩展会话。嗯,文档里写得很清楚,就是没仔细看。
  • NRC 0x13(消息长度或格式错误):这个相对好查。检查一下你发的报文,数据长度对不对?比如10 03后面是不是多了一个字节?或者少了一个?
小技巧: 遇到会话切换失败,别急着改代码。先抓个CAN log,看看ECU回复的NRC是什么。很多时候,问题就出在请求报文本身。我曾经见过一个案例,工程师把10 02发成了10 02 00,多了一个无效字节,ECU直接回了0x13。排查了整整一天,最后发现是多打了一个空格。

2.2 默认/扩展/编程会话的权限管理:谁该干什么?

UDS定义了三种标准会话:默认会话(Default Session, 0x01)、扩展会话(Extended Session, 0x02)和编程会话(Programming Session, 0x03)。它们就像三个不同权限的房间,能做的事情完全不一样。

会话类型 会话ID 典型用途 可执行的服务示例
默认会话 0x01 ECU上电后的默认状态,用于常规通信和读取基本数据 0x22(读取数据)、0x19(读取DTC)
扩展会话 0x02 用于更复杂的诊断功能,如写入数据、执行例程 0x2E(写入数据)、0x31(例程控制)
编程会话 0x03 用于ECU软件刷写、Bootloader操作 0x34(请求下载)、0x36(数据传输)、0x37(请求退出传输)

你想想看,如果默认会话就能刷写程序,那岂不是乱套了?任何诊断仪都能随便改ECU的软件,安全性何在?所以,权限管理是必须的。

避坑指南: 我曾经见过一个项目,工程师在扩展会话里实现了刷写功能,结果被客户打回来重做。为什么?因为ISO 14229标准里,刷写相关的服务(0x34、0x36等)只能在编程会话下执行。扩展会话虽然权限比默认高,但也不能越俎代庖。所以,设计会话权限时,一定要严格遵循标准。

另外,会话切换是有“方向性”的。通常,从默认会话可以切到扩展或编程会话。但从编程会话切回默认会话,可能需要先经过扩展会话。这取决于ECU的具体实现。我建议,在开发初期就把会话状态机画清楚,避免后期逻辑混乱。

2.3 超时机制:别让ECU一直等着

超时机制是0x10服务里一个容易被忽视,但极其重要的部分。ECU不是无限期地等你发下一条指令的。如果超时了,它会自动切回默认会话。这其实是一种安全保护机制。

UDS标准里定义了三个关键的定时器:

  • S3Server(默认会话超时):ECU在非默认会话(扩展或编程)下,如果超过这个时间没有收到任何诊断请求,就会自动切回默认会话。典型值是5000ms。
  • S3Client(客户端超时):诊断仪(Tester)等待ECU响应的超时时间。如果ECU没在规定时间内回复,Tester会认为通信失败。
  • P2Server(响应超时):ECU处理一个请求并给出响应的最大时间。如果处理时间超过P2Server,ECU必须先发一个NRC 0x78(请求正确接收,正在处理),然后再发最终的响应。
注意: S3Server超时是很多问题的根源。比如,你在编程会话里刷写一个大文件,刷写过程本身可能超过S3Server时间。如果ECU在刷写过程中因为超时切回了默认会话,那刷写就会失败。正确的做法是,在刷写过程中,Tester需要周期性地发送“保持激活”报文(比如10 02或3E 00),告诉ECU:“我还活着,别切回去。”

我记得有一次,一个同事在调试刷写流程时,总是刷到一半就失败。查了半天,发现是刷写时间超过了S3Server的5000ms。ECU在刷写过程中自动切回了默认会话,导致后续的数据传输全部被拒绝。解决方案很简单,在刷写循环里加一个定时发送3E 00的机制,问题就解决了。

嗯,这里要注意,S3Server的值不是固定的。有些ECU为了安全,会把编程会话的S3Server设得很短,比如1000ms。这就要求Tester的“保持激活”报文发送频率要足够高。否则,稍微一卡顿,会话就丢了。

核心总结:
  • 会话切换失败,先看NRC,再查文档。
  • 权限管理要严格遵循标准,默认、扩展、编程各司其职。
  • 超时机制是安全底线,务必在Tester和ECU两端都实现好。

好了,关于0x10服务,我们就聊到这里。下一节,我们会深入探讨安全访问(0x27)服务,那又是一个充满“坑”的地方。到时候见。