2.3 诊断会话控制(0x10)——挂哪个科的号
场景:你把车停在维修工位上
你是一个诊断仪。你的面前是车——它里面住着几十个ECU,每一个都在正常运转。你通过OBD插座把诊断线接到CAN总线上——现在,你对整辆车来说是一个陌生人。
默认状态下,你处于默认诊断会话(defaultSession)。你可以在默认会话里读取故障码(0x19),可以读取DID(0x22),可以清除DTC(0x14),可以向ECU发TesterPresent——但你不能修改配置参数,也不能执行任何主动控制(输入输出控制、例行控制)。默认会话是一个公共可读空间——任何人在任何时间插上诊断口都能进入。不需要授权,不需要声明身份。
如果你想在ECU上执行更敏感的操作——比如写入VIN码、重新校准转向角传感器、触发ABS泵自检,或者最危险的——刷写固件——你必须离开默认会话。
离开默认会话的唯一方式,就是发送一条诊断会话控制(0x10)请求。
四种会话——但为什么要四种
ISO 14229-1:2013定义了四种标准诊断会话:
| 子功能码 | 会话名称 | 中文 | 类比医院 |
|---|---|---|---|
| 0x01 | defaultSession | 默认会话 | 公共大厅——任何人在此只能查看,不能操作 |
| 0x02 | programmingSession | 编程会话 | 手术室——专为刷写/编程操作设计 |
| 0x03 | extendedDiagnosticSession | 扩展诊断会话 | 诊察室——允许主动检测和控制 |
| 0x04 | safetySystemDiagnosticSession | 安全系统诊断会话 | 军管区——气囊等关键安全系统 |
此外,车厂可以在0x40-0x5F范围内定义自己的自定义会话,系统供应商在0x60~0x7E范围内。
| 会话 | 典型用途 |
|---|---|
| 默认(0x01) | 日常OBD-II排放检测、快速读DTC、读VIN |
| 扩展(0x03) | 故障排查(读DID、IO控制、例行自检)、标定参数调整 |
| 编程(0x02) | 固件刷写(OTA或售后)、出厂首次编程 |
| 安全系统(0x04) | 气囊系统诊断、转向角传感器标定、ESP液压单元排气 |
为什么是四种而不是三种或五种? 这不是标准委员会拍脑袋决定的数字——它们对应四个互不重叠的权限域:
-
默认(0x01):零权限。“谁都能进。“任何诊断仪不用发0x10就能处于这个会话(因为ECU上电后默认在此会话)。这时你能做的事被限制在只读诊断数据。你不能改变任何ECU的行为。
-
扩展(0x03):诊断权限。“你是技师,你可以做检查。“你能读取数据、能执行主动控制(IO Control和Routine Control)、能开启或关闭某些通信源——但你还不能写Flash,也不能操作安全气囊之类的硬安全系统。这是诊断工作中最常用的会话——在扩展会话里,你可以做几乎所有的“检查和轻度治疗”。
-
编程(0x02):刷写权限。“你是工厂或OTA,你可以写入新固件。“这个会话专为固件升级设计。进入编程会话后,ECU停用所有高层应用通信(NM、周期CAN帧等)——因为总线不能同时承载大块诊断数据和正常应用帧。DTC状态更新也会被暂停(不是DTC被清除——是ECU暂时不再检测新的故障)。从诊断仪的角度,编程会话就是“手术室”——进去就是做刷写操作的,做完就退出来。
-
安全系统(0x04):硬安全权限。“你是安全系统专家,你可以触碰气囊、安全带预紧器、转向辅助。“这个会话隔离于OBD-II和普通诊断仪——它只被授权诊断仪访问,且一般连上特定的ECU(气囊ECU、转向ECU、ESP/ABS液压单元ECU)。普通诊断请求在这里是无权限的——除非ECU判断你是“站在特定的科室、有特殊的地方可操作”。
核心洞察:四个会话不是随机的数字枚举——它们是一个权限升阶过程。0x01→0x03→0x02/0x04。每一级解锁的下一级都包含一组更敏感的操作。这是为什么任何一次会话切换都会自动将安全等级复位到锁定态。因为新状态可能有不同的安全边界——上一次会话里你解锁的权限在这一次会话不一定适用于不同的操作。
请求和响应报文
请求:0x10 + sub-function
Byte 0: 0x10 (SID)
Byte 1: diagnosticSessionType (SubFunction)
bit7 = suppressPosRsp (1=不需要正响应)
bit6-0= session type
0x01 = defaultSession
0x02 = programmingSession
0x03 = extendedDiagnosticSession
0x04 = safetySystemDiagnosticSession
例:0x10 0x03 → 请求进入扩展诊断会话,需要正响应。
例:0x10 0x83 → 请求进入扩展诊断会话,不需要正响应(bit7=1)。
正响应:0x50 + 0x03 + sessionParameterRecord
正响应的前两个字节与请求一致(回声子功能码)。后四个字节是会话参数记录:
Byte 0: 0x50 (SID+0x40)
Byte 1: 0x03 (会话类型回声)
Byte 2-3: P2Server_max (ms, 2字节, 高字节在前)
Byte 4-5: P2*Server_max (10ms单位, 2字节, 高字节在前)
P2Server和P2*Server这两个定时参数的含义会在下一段详细展开。现在先知道:ECU在正响应里告诉诊断仪——“我的回复速度的上限是X毫秒”——诊断仪的等待逻辑基于这个值。
P2和P2*——等待的两个时间维度
在UDS通信中,有两个时间参数控制诊断仪的等待超时:
| 参数 | 含义 | 默认值 | 诊断仪行为 |
|---|---|---|---|
| P2server | ECU执行请求并返回最终响应的最大时间 | 50ms(通常) | 诊断仪的接收等待计时器基于此值;超时→视为通信故障 |
| P2*server | ECU在NRC 0x78 (responsePending)后返回最终响应的最大时间 | 5000ms(通常,可以协商) | 过了P2server之后诊断仪继续等待的总时间上限 |
P2和P2*的区别,用一个时间线来说最清晰:
诊断仪 ECU
│ 请求 │
├──────────────────────────>│ 开始处理...
│ │
│ ←P2server→计时器开始计数
│ │
│ │ 处理尚未完成——不能用最终结果回答
│ 0x7F 0xSID 0x78 │
│<──────────────────────────┤ "等着" (NRC 0x78 responsePending)
│ │
│ ←──── P2*server ────> │ 切换到增强等待时间 (更长的)
│ │
│ │ 处理完毕
│ 0x50+正响应 │
│<──────────────────────────┤ 最终响应
核心洞察:如果ECU知道自己在第一个P2窗口内无法完成请求,它给诊断仪发NRC 0x78——“我收到了,我在做——但不是现在的P2时间窗内——你等我P2的时间。” 这就像你问医生一个问题——医生说“这是个好问题,让我查下你的完整的检测记录再回答你——在那之前,不要走开。“ 为什么是0x78和P2?因为车用诊断仪如果一直无响应地等——几千毫秒的空白会让诊断仪判断为通讯中断而重试(浪费总线)。所以ECU主动发出“等着“——就看你有没有耐心。
S3——你不发保活,就自动注销挂号
这是诊断会话控制里最容易被人漏掉的一个暗坑——非默认会话不是永久有效的。
当ECU进入非默认会话后,启动一个倒计时器——S3server超时。如果在这个定时器倒计时到0之前,ECU没有收到任何诊断请求消息——ECU自动切换回默认会话,并将安全等级复位到锁定态。
典型S3server值:2000ms~5000ms(取决于ECU配置)。
时间线:
T=0 诊断仪发 0x10 0x03 → 进入扩展会话
S3定时器启动 (5000ms)
T=3000 诊断仪发 0x22 0x01 0x0C (读发动机转速)
S3定时器重置→5000ms
T=8000 诊断仪发 0x3E 0x00 (读TesterPresent心跳)
S3定时器重置→5000ms
...
T=62000 诊断仪太久没发任何请求
S3定时器→0
ECU 自动切回默认会话 (session=0x01)
安全等级→LOCKED
ECU 停止诊断功能、恢复所有正常应用通信
核心洞察:S3的引入是基于一个极其务实的工程现象——诊断仪随时可能断开。OBD线松动、诊断电脑死机、维修厂停电、客户不小心拔了OBD插头——ECU不能一直在扩展/编程/安全会话中等待一个永远不会再回来的诊断仪。Dead Man’s Switch——如果你不主动证明你还在线,我就回到最安全的状态。
这就是为什么诊断仪需要每几个周期发一次TesterPresent(0x3E)——0x3E是一个无副作用的轻量请求,专门用于重置S3定时器,不做任何诊断操作。纯粹是为了告诉ECU“别超时,我还在“。这在第2.4节会专门讲。
会话侧的非可逆效应
切换会话不是一个无副作用的操作。进入新会话时,ECU必须自动执行以下:
1. 安全等级锁定
从任何会话切换到另一个会话时——即使是从扩展会话切到编程会话——安全等级复位到LOCKED(0x00)。你必须重新执行0x27 SecurityAccess解锁。这避免了“上一次会话的权限意外沿用到新的会话“的危险。
2. ResponseOnEvent停止
如果诊断仪在之前的会话里注册了ResponseOnEvent(0x86)事件监听——切换会话时这些事件监听全部停止。新会话需要重新注册。
3. 通信管理复位
如果之前的会话通过CommunicationControl(0x28)禁用了某些通信——进入新会话后通信自动恢复为正常模式。这是为了避免“在编程会话中关掉的通信在默认会话中仍然是关的“遗留——通过0x28禁用通信的效果只持续到当前会话结束。
4. DTC设置控制复位
如果之前在某个会话里通过ControlDTCSetting(0x85)停止了DTC状态位更新——进入新会话后恢复为“DTC设置启用(on)“的正常模式。
核心洞察:这四步构成了会话隔离的完整性——你不能依赖“上次会话的结果在这次生效“。每一次会话切换都是一次干净的状态页清空。这个设计看似乏味——但正是它保证了诊断仪和ECU不会在跨会话状态不一致时掉入“上一个会话留下一个锁没有解“的暗坑。
编程会话的特殊性
编程会话(0x02)是四个会话里最特殊的一个——它为Flash刷写做了大量特定的优化:
- P2/P2*定时器参数通常调大——Flash擦除可能需要几百毫秒到几秒。
- ECU自动停用所有周期性应用通信——NM、周期CAN帧全部关笔。编程会话期间ECU不说“我现在在怠速“——它在专心下载。
- DTC检测自动化暂停——不是因为故障消失了,而是因为刷写操作会造成各种电压波动、瞬间通信中断——这些不是真实故障,不需要写入DTC存储。ControlDTCSetting(0x85)通常在编程会话的开头自动发送一次(很多工具会显式发0x85 0x02关闭DTC检测)。
- 通常不允许0x22读DID——因为ECU在编程会话中已经停止运行正常应用——DID对应的传感器数据和计算值已经不可靠或不存在。
退出编程会话的正确方式是: 先发0x11复位(keyOffOnReset或hardReset),ECU启动后自动回到默认会话。如果ECU不带自动复位——你需要手工发0x10 0x01切回默认。
核心洞察:编程会话像一个“麻醉状态“——病人失去知觉但大脑仍在执行指令,身体在不受其他刺激的情况下被修改。麻醉状态下你不能指望病人给你正常的问答——所以读DID和正常通信都关掉了。修改完后你不能突然把病人叫醒——你必须先恢复稳定性(写入固件→验证CRC→ECU复位→进入新默认会话)——这也是“刷完后为什么要复位“的根因。
请求与响应的完整示例
正常流程——进入扩展诊断会话:
诊断仪 → ECU: 0x10 0x03
ECU → 诊断仪: 0x50 0x03 0x00 0x32 0x00 0xFA
P2server = 0x0032 = 50ms。P2server = 0x00FA = 250 × 10ms = 2500ms(P2单位是10ms)。
异常——请求不支持的子功能:
诊断仪 → ECU: 0x10 0x05 (不存在此会话)
ECU → 诊断仪: 0x7F 0x10 0x12 (负响应: 子功能不支持)
异常——编程会话不能从“当前状态“直接切换:
某些ECU需要先复位才能在编程会话中被刷写——诊断仪发了0x10 0x02,ECU发现当前不适合进入编程会话:
诊断仪 → ECU: 0x10 0x02
ECU → 诊断仪: 0x7F 0x10 0x22 (负响应: 条件不满足)
本篇小结
- 四种诊断会话构成权限升阶——default→extended→programming/safety。每一次升阶解锁下一级的敏感操作,同时自动复位安全等级到LOCKED。
- P2和P2*是两段时间窗口——前者是ECU正常响应的时间上限;后者是ECU发出“等着“(NRC 0x78)后的延长时间上限。两者在正响应中被ECU宣告给诊断仪。
- S3定时器强制诊断仪持续发保活——如果你不在非默认会话中活动,ECU定时把你踢回默认。这是Dead Man’s Switch工程实践的核心。
- 编程会话(0x02)是最特殊的会话——它包含自动停止应用通信、自动暂停DTC检测、加长P2/P2*——这些都是为了给Flash刷写提供最干净的业务通道。
【下集预告】:挂号之后,你得不停地跟ECU证明一件事——’我还在。我没掉线。我电脑没死机。’这个证明的方式就是TesterPresent(0x3E)——UDS协议里最简单、最短、最容易被忽视但也是最关键的一个SID。没有它——你进了扩展会话5秒后就自动回到默认了。你的小命全在0x3E上。