UDS由ISO-14229系列标准定义,ISO 14229-1 定义了诊断服务,不涉及网络及实现,只有应用层的内容。而ISO 14229-3则定义了UDS在CAN总线上的实现。
诊断通信的过程从用户角度来看非常容易理解,诊断仪发送诊断请求(request),ECU给出诊断响应(response),而UDS就是为不同的诊断功能的request和response定义了统一的内容和格式。
最近关于UDS的一系列专栏文章只关注应用层的诊断服务,忽略下层的通信机制。
Diagnostic request的格式:
Diagnostic request的格式可以分为两类:一类是拥有sub-function的,另一类是没有sub-function的,如下面两张图所示。Service ID(以下简称SID)的长度固定为1个字节,代表了这条诊断命令执行的什么功能。sub-function的长度也是1个字节,它通常表示对这个诊断服务的具体操作,比如是启动、停止还是查询这个诊断服务。而后面的parameter则根据各个诊断服务的不同具有不同的内容,长度和格式并没有统一规格,它用于限定诊断服务执行的条件,比如某个诊断服务执行的时间等。parameter的一个重要应用是作为标识符,标识诊断请求要读出的数据内容,我会在后续的文章里详细讲述各个诊断服务的应用。
拥有sub-function的诊断请求
无sub-function的诊断请求
有一点要补充的是,其实sub-function严格来说是7个bit,而不是1个byte,因为它的最高位bit被用于抑制正响应(suppress positive response,SPR),如果这个bit被置1,则ECU不会给出正响应(positive response); 如果这个bit被置0,则ECU会给出正响应。这样做的目的是可以告诉ECU不要发不必要的response,从而节约通信资源。
Diagnostic response的格式:
Diagnostic response分为positive和negative两类。positive response意味着诊断仪发过来的诊断请求被执行了,而negative response则意味着ECU因为某种原因无法执行诊断仪发过来的诊断请求,而无法执行的原因则存在于negative response的报文中。
positive response
positive response的格式如上图所示,也基本上是由三部分组成,其中的response SID这个字节作为诊断请求的echo,它等于SID + 0X40。后面的两个部分则视具体的诊断服务而定。
negative response
negative response的格式固定为3个字节,第一个字节为0x7F,第二个字节是被拒绝掉的SID,第三个字节是这个诊断服务无法被执行的原因。下面这张图列举了部分原因代码,比如,如果ECU给出7F 22 13这个negative response,则说明22这个服务因为诊断请求数据长度不对的原因无法执行。
Negative Response Code
总结:诊断通信的过程就是诊断仪和ECU交换数据,前者发的是request,后者发的是response,而UDS最重要的作用就是定义了这些request和response的格式和内容。今天这篇文章对request和response进行了简要介绍,在后面描述各种诊断服务的文章中我会通过更多的示例来说明这两个基本概念。
UDS定义的诊断服务从逻辑来说分为以下几类:
- Diagnostic and Communication Management (诊断和通信管理)
- Data Transmission (数据传输)
- Stored Data Transmission (存储数据传输,用于操作DTC)
- InputOutput Control (IO控制)
- Routine Control (不知如何翻译好,作用是调用ECU内部的预置函数)
- Upload Download (上传下载)
UDS规定使用1个byte来表示诊断服务,即所谓的Service ID,简称SID。本文介绍一下Diagnostic and Communication Management 这一类诊断服务中的一部分。
DiagnosticSessionControl (0x10)
DiagnosticSessionControl诊断request的格式
DiagnosticSessionControl这个服务的SID是0x10,request固定为2个byte,第一个byte是SID,第二个byte的低7bit是sub-function,用于指示ECU将进入的session。UDS定义的session包括:
0x00 ISOSAEReserved(保留)
0x01 defaultSession
0x02 ProgrammingSession
0x03 extendedDiagnosticSession
0x04 safetySystemDiagnosticSession
0x05 – 0x3F ISOSAEReserved(保留)
0x40 – 0x5F vehicleManufacturerSpecific(由整车厂自定义使用)
0x60 – 0x7E systemSupplierSpecific(由ECU供应商自定义使用)
0x7F ISOSAEReserved(保留)
DiagnosticSessionControl用于控制ECU在不同的session之间进行转换,session可以看作是ECU所处的一种软件状态,在不同的session中诊断服务执行的权限不同。 ECU上电之后,默认处在defaultSession中,在这个session中很多诊断服务不可以执行,很多诊断相关的数据不能读取或写入。一般的诊断仪启动之后,会给ECU发送10 03,即让ECU进入 extendedDiagnosticSession中,在这个session中可执行的诊断服务就很多了。而如果要让ECU保持在non-defaultSession中,则需要诊断仪每隔固定的时间发送0x3E服务,ECU才会知道诊断仪有和自己通信的需求,从而保持在non-defaultSession中。另一个常用的session是ProgrammingSession,在这个session中可以进行软件刷写的一系列诊断服务。0x40 – 0x5F 这个范围中的session由整车厂自定义使用,比如,某些诊断服务或诊断数据的操作需要在生产线上执行,即所谓的End-Of-Line,整车厂可以从这个范围中选择一个值来表示EOL session;又或者在开发阶段需要某种“超级”session,则也可以从这里选一个值用来使ECU进入开发模式的session。DiagnosticSessionControl这个服务非常简单,但是它却是ECU和诊断通信的第一条诊断命令。
DiagnosticSessionControl诊断response的格式
这个诊断服务的response分为三部分,第一部分是0x50,作为SID的echo;第二部分是进入的session,作为sub-function的echo;第三部分是4个字节,前两个字节代表P2Server_max,即ECU在应用层上对诊断命令的响应时间,后两个字节代表P2*Server_max
,即ECU在暂时无法处理当前诊断命令(具体表现为发送了NRC 0X78),在应用层上对诊断命令响应的最长时间。
ECUReset (0x11)
ECUReset 这条指令的用途是通过诊断请求使ECU重启。
ECUReset 诊断request的格式
ECUReset 这个服务的SID是0x11,request固定为2个byte,第一个byte是SID,第二个byte的低7bit是sub-function,用于指示ECU将模拟哪种方式进行重启。
常用的sub-function包括(只举2个例子,UDS还定义了很多其他的值)
0x01 hardReset 模拟KL30的重启
0x02 keyOffOnReset 模拟KL15的重启
当我们通过诊断命令改写了ECU的某些数据,或者对ECU进行了某些设置,只有将ECU重启才能将这些配置生效,所以就有了这个诊断命令。在ECUReset 执行之后,ECU会从Non-defaultsession回退到defaultsession中。
SecurityAccess (0x27)
厂家可能会为ECU定义某些安全级别稍微高一些的诊断服务,在执行此类服务之前,就需要执行SecurityAccess 这个诊断命令,进行一个简单的身份验证。
完成SecurityAccess 有以下步骤:
- 诊断仪向ECU请求“Seed”(通常是一个与时间相关的伪随机数),
- ECU向诊断仪发送“Seed”,
- 诊断仪向ECU发送“Key” (根据请求得到的Seed和一个本地的密码进行计算得来)
- ECU判断诊断仪发来的“Key”是否有效
根据UDS的定义,0x03, 0x05, 0x07 – 0x41 这个范围留给用于requestSeed的sub-function;0x04, 0x06, 0x08 – 0x42这个范围留给用于sendKey的sub-function。具体选择哪对值,由整车厂自己定义。整车厂也可以选择多对sub-function,用于不同等级的安全访问。
下面我举一个完成SecurityAccess的诊断命令的例子,假设0x05用于requestSeed,0x06用于sendKey。
诊断仪发送 27 05
ECU响应 67 05 01 01 01(seed是 01 01 01)
诊断仪发送 27 06 02 03 04(key值是02 03 04,seed是 01 01 01,假设本地密码为01 02 03,而算法就是将密码与seed相加)
ECU验证成功 67 06
此时ECU就处于unlocked的状态了,那些被保护起来的诊断服务和诊断数据可以被操作了。通常来说,如果ECU重启,或者回到了default session,unlocked状态就失效了,如果要执行相关诊断服务,则需要再次执行上面描述的过程。
CommunicationControl (0x28)
该服务用于打开/关闭某些类别的报文的发送/接收。它通常在刷写软件或大量数据的时候使用,因为在刷软件或参数的时候并不需要ECU进行与通信相关的功能,将通信关闭之后可以把所有通信资源都留给软件或参数的下载,当下载过程完成之后再利用该服务将通信恢复即可。
0x28服务的格式如下图所示
0x28服务的格式
第一部分即SID,一个byte,值为0x28;
第二部分是sub-function,表明要对ECU的通信进行哪种控制,具体包括 :
0x00 enableRxAndTx (激活接收和发送)
0x01 enableRxAndDisableTx(激活接收和关闭发送)
0x02 disableRxAndEnableTx(激活发送和关闭接收)
0x03 disableRxAndTx(关闭接收和发送)
0x04 enableRxAndDisableTxWithEnhancedAddressInformation(激活接收和关闭发送,针对特定的地址)
0x05 enableRxAndTxWithEnhancedAddressInformation(激活接收和发送,针对特定的地址)
0x06 - 0x7F都是保留或者留给厂商自定义的。
第三部分表明这条诊断请求要对哪种报文进行控制,长度为1个byte,定义如下表所示:
communicationType的定义
这个byte中最常用的就是低2 bit,0x1代表普通应用报文,0x2代表网络管理报文,0x3代表普通应用报文和网络管理报文。
第四部分是optional的,只有当sub-functional等于0x04或0x05时才需要使用。
举个完整的诊断服务例子:
28 01 01 表示激活应用报文的接收并关闭应用报文的发送(网络管理报文不受影响)。
28 00 01 表示激活应用报文的接收和发送(网络管理报文不受影响)。
TesterPresent (0x3E)
这个诊断服务的用处可以通过它的名字很明显地得知,即告知ECU诊断仪还在连接着。在上一篇文章中我说到了关于session的部分,如果没有诊断命令的发送和接收,ECU将从non-default session中回退到default session, 0x3E就是用于使ECU保持在当前session。
这应该是UDS中最简单的一个诊断服务了,它永远只有两个byte,格式如下:
0x3E诊断服务的格式
当sub-function是0x00时,ECU要给出response;当sub-function是0x80时,ECU不需要要给出response。
一般来说主机厂会为这个服务定义两个时间参数,一个参数用于规定自己的诊断仪发送0x3E服务的间隔,另一个参数用于定义ECU收不到0x3E服务的timeout时间。
ControlDTCSetting (0x85)
该服务用于控制ECU的DTC存储,这个服务常常和前面提到的28服务一起使用,比如,在开始写参数之前,为了获得更快的传输速度,我们用28服务把所有ECU的通信关闭了,但此时因为收到不到相关的报文,ECU会没有必要地存储很多DTC,这时如果我们使用85服务把ECU存储DTC的功能暂时性地禁止掉,则不会造成这种麻烦。
0x85服务的格式
第一部分即SID,一个byte,值为0x85;
第二部分是sub-function,表明是打开还是关闭ECU的DTC存储,具体包括 :
0x01 on
0x02 off
第三部分是optional的,由各家自己定义,比如,可以用FF FF FF 来表示这条诊断命令针对所有的DTC。
ResponseOnEvent (0x86)
我在以前的文章里说,诊断通信过程是问答式的,诊断仪发请求,ECU给响应。0x86服务算是一个例外,在ECU收到这条0x86服务之后,当DTC产生时,它会自动地上报DTC及相关环境数据,直到用另一条0x86服务来关闭ECU的这个行为。
该功能主要用于ECU的前期开发阶段,在售后和生产中是不会用到的,而且该服务的格式复杂(即可变的参数很多),执行它还分为好几个步骤,我就不详细写了。
LinkControl (0x87)
这个服务用于转化ECU数据链路层和物理层的状态,比如,在高速CAN上的ECU正常通信速率是500 kbit/s,但它同时也支持1M bit/s的波特率,如果需要刷写大量数据,便可以利用这条诊断服务让ECU以1M bit/s的波特率进行通信。
这个诊断服务的执行分为两个步骤:
- 验证ECU是否支持要调整到的目标波特率
- 让ECU的数据链路层和物理层转到目标波特率的通信状态
只有当第一个步骤验证通过了,第二个步骤才可以成功执行。
这篇文章介绍一下UDS的第二类诊断服务,即Data Transmission (数据传输)。这类诊断服务包括以下SID:
ReadDataByIdentifier (0x22)
ReadMemoryByAddress (0x23)
ReadScalingDataByIdentifier (0x24)
ReadDataByPeriodicIdentifier (0x2A)
DynamicallyDefineDataIdentifier (0x2C)
WriteDataByIdentifier (0x2E)
WriteMemoryByAddress (0x3D)
通常,0x22和0x2E成对使用,0x23和0x3D成对使用,这几个服务用于诊断数据的基本读写操作。0x24,0x2A,0x2C是一些特殊操作。
0x22和0x2E这两个服务是对以标识符(identifier)标记的数据的操作,前者是读,后者是写。UDS规定,诊断数据使用两个byte的标识符来标记,比如,0xF187用来标记ECU的零件号,0xF19E用于标记该ECU所使用的诊断文件的名字,UDS还规定了厂家可以自定义的标识符范围。这两个服务的用法很简单,下面我以读取ECU的零件号为例说明:
22 F1 87 (读取零件号)
62 F1 87 XX YY ZZ KK MM NN(给出零件号)
具体每次可以使用22服务读取几个ID,每个ID的读写权限(比如在哪些session中可以读写,是否需要安全访问操作等),由厂家自定义。假设零件号这个ID是可以写入的话,则写零件号的诊断命令是:
2E F1 87 XX YY ZZ KK MM NN(写入零件号)
6E F1 87(给出positive response)
0x23和0x3D这两个服务是对以地址信息(memoryAddress )标记的数据的操作,前者是读,后者是写。这个命令的格式稍微复杂一点。以0x23为例,它的诊断请求格式是:
0x23服务的请求格式0x23
第一部分固定为1个byte, 0x23;
第二部分是格式信息,长度为1个byte,高4 bits用于指示memorySize的长度(字节数),低4 bits用于指示memoryAddress的长度(字节数)。比如,如果这个值为0x46,则后面的memorySize为6个byte,memoryAddress为4个byte。
第三部分是memoryAddress信息,它的长度由第二部分的AddressAndLengthFormatIdentifier指示。
第四部分是memorySize信息,它的长度由第二部分的AddressAndLengthFormatIdentifier指示。
如果这条命令的格式是 23 22 xx yy aa bb,则它的含义就是,读取xx yy地址的长度为aa bb的数据。
了解了0x23的用法,0x3D的用法就很好理解了,它标识memoryAddress和memorySize的方法与0x23相同,只是在诊断命令最后再加上一段需要写入的数据。
这篇文章介绍Stored Data Transmission (存储数据传输,用于操作DTC)这一类诊断服务,涉及到两条诊断命令,分别是:
0x14:ClearDiagnosticInformation
0x19:ReadDTCInformation
这两条服务用于操作存储在ECU中的DTC,使用频率很高,而且它们比较好地体现了“诊断”两个字的含义。
0x14:ClearDiagnosticInformation
这条诊断命令的格式比较简单,用法也很好理解,即删除存储在ECU中的DTC。
0x14诊断命令请求的格式
第一个字节就是SID了,后边的三个字节用于标识将要被删除的DTC种类,UDS规定用FF FF FF表示所有种类的DTC,由厂家自定义代表Powertrain、Chassis、、Body、Network Communication等种类DTC的值。
比如,14 FF FF FF这条指令表示的就是删除掉ECU中的所有DTC。ECU只需要返回一个0x54表示成功执行即可。
0x19:ReadDTCInformation
这条指令用于读取存储在ECU中的DTC,它的格式如下
0x19诊断命令请求的格式0x14诊断命令请求的格式
0x19服务的sub-function代表了各式各样读取DTC的方法,UDS给19服务的sub-function从0x00到0x19进行了明确定义,我只使用过其中4种,下面对我用过的这些进行介绍,如果大家对其他的感兴趣,可以查阅ISO 14229的定义。
sub-function = 0x01 (reportNumberOfDTCByStatusMask)
sub-function = 0x01用于读取符合特定条件的DTC数量,此时parameter为一个byte的Mask,用于与DTC的Status进行“与”运算,而ECU返回的则是"与"运算之后结果不为0的DTC的数量。DTC的Status用一个byte表示,其中的8个bit分别代表DTC的不同状态,比如,bit 0 表示这个DTC是active的还是passive的,bit 4表示这个DTC是否已经被confirm了,如果DTC的状态是confirm,则说明该DTC已经被ECU存储下来了。
比如:19 01 08这个命令的用途,就是读取所有状态为confirm的DTC的数量。
sub-function = 0x02 (reportDTCByStatusMask)
sub-function = 0x02用于读取符合特定条件的DTC列表,此时parameter仍然为一个byte的Mask,用于与DTC的Status进行“与”运算,而ECU返回的则是"与"运算之后结果不为0的DTC列表。
比如19 02 01这个命令的用途,就是读取所有状态为active的DTC的数量。此时ECU返回的格式应该是59 02 01 XX XX XX 01 YY YY YY 09......。返回的DTC列表中的每个条目为4个字节,前三个字节用于标识DTC,比如 XX XX XX,最后一个字节用于标识DTC状态,比如01,表示DTC是active的,09表示DTC是active且confirm的。
sub-function = 0x06 (reportDTCExtDataRecordByDTCNumber)
sub-function = 0x06用于读取某个DTC及其相关的环境数据,此时parameter为4个byte,前三个byte用于标识我们要读取的DTC,第四个byte用于标识要读取的环境数据的范围,UDS规定使用FF来表示读取所有的环境数据,各厂家可以要根据自己的需求定义其他的值来代表要读取的环境数据的范围。环境数据包括DTC状态,优先级,发生次数,老化计数器,时间戳,里程等,厂家还可以根据自己的需求定义一些此DTC产生时的测量数据。
比如 19 06 XX XX XX FF就表示读取 XX XX XX这个DTC的所有环境数据,ECU的返回值应该是59 06 XX XX XX AA BB CC DD.....,其中AA BB CC DD...代表的就是XX XX XX这个DTC产生时所一起存储的环境数据。
sub-function = 0x0E(reportMostRecentConfirmedDTC)
sub-function = 0x0E时,不需要parameter。0x0E表示,要求ECU上报最近的一条被置为confirm的DTC。我在《统一诊断服务 (Unified diagnostic services , UDS) (三)》一文中介绍过0x86服务,sub-function = 0x0E的19服务通常被作为参数传递给86指令,要求ECU在发生DTC存储的时候进行自动上报,即19 0E这两个字节的指令被嵌入到86服务的命令中。这条命令在开发阶段会用到,比如验证某个故障路径是否生效。
这篇文章将介绍InputOutputControlByIdentifier (0x2F) 和RoutineControl (0x31) 这两个诊断服务的用途和用法。它俩的作用有点类似,都是调用ECU内部一些预定义的操作序列,相当于是我们从外部利用诊断手段控制ECU的接口。
InputOutputControlByIdentifier (0x2F)
ECU简单来说就是一个对输入(sensor)进行计算再产生输出(actuator)的系统。2F这个服务就是对ECU的输入和输出进行控制。这个服务在生产线上会需要使用,比如,在总装阶段,工人需要验证车上的各种功能是否正常,例如四个车窗的升降是否正常,如果挨个开关去按,那效率很低,如果通过一个诊断命令就能够观察到车窗升降的情况,效率则高得多。
ECU就是一个处理输入信息、输出控制的系统
比如,ECU接收一个输入信号A,我们就可以利用2F给这个A赋个我们需要的值;ECU对某个执行器B进行控制,我们就可以利用2F服务再配上某些特定的参数来实现对B的控制,例如门控对车窗升降、后视镜折叠等的控制。
2F命令的格式
2F服务的request由4部分组成
- SID
- dataIdentifier,用于标识被控制的IO对象
- controlOptionRecord,用于标识控制方式,比如是启动、停止控制,还可以有一些自定义的参数来进行更精准的控制,比如让某个执行器的动作持续多长时间。controlOptionRecord又分为两部分,分别是1个byte的inputOutputControlParameter,以及若干byte由厂家自定义使用的controlState。
- controlEnableMaskRecord,这是一个可选参数,用于标识controlOptionRecord中的哪些parameter被使用。
UDS明确定义了四种inputOutputControlParameter
0x00 returnControlToECU (将控制权还给ECU,即结束控制)
0x01 resetToDefault (将dataIdentifier所引用的输入信号、内部参数、输出信号等设为默认值)
0x02 freezeCurrentState(将dataIdentifier所引用的输入信号、内部参数、输出信号等冻结住)
0x03 shortTermAdjustment (将dataIdentifier所引用的输入信号、内部参数、输出信号进行设置,其实就相当于开始了对ECU的控制)
另外,UDS定义可以用22服务读取2F服务中使用的dataIdentifier,返回值是状态信息,具体的状态信息是什么,则由使用者自定义了。
我们以14229中举的一个例子来感受一下2F服务:
这个例子是使用2F控制Air Inlet Door Position (进气口门位置),用标识符0x9B00来标识进气口门的位置。Air Inlet Door Position [%] = decimal(Hex) * 1 [%] ,即用一个百分比来表示这个位置。
step1:
tester 发送22 9B 00读取当前进气口门的位置
ECU返回62 9B 00 0A , 0x0A = 10(dec),表示当前位置是10%
step2:
tester 发送2F 9B 00 03 3C ,表示要将进气口门的位置调整到60%,0x3C = 60(dec)
ECU返回6F 9B 00 03 0C,表示接受控制,当前进气口门的位置为12%。因为ECU收到请求后是立刻响应的,而门的位置调节需要时间,所以还没有达到60%。
step3:
过一段时间后tester 发送22 9B 00读取当前进气口门的位置
ECU返回62 9B 00 3C , 0x3C = 60(dec),表示当前位置已经到了60%
step4:
tester 发送2F 9B 00 00,将控制权交还给ECU
ECU返回6F 9B 00 00 3A,表示接受请求,当前位置为58%
step5:
tester 发送2F 9B 00 02,冻结9B 00这个ID所代表的进气口门位置这个状态
ECU返回6F 9B 00 02 32,表示接受请求,当前位置保持在50%
RoutineControl (0x31)
31服务是调用ECU内置的一些操作序列的接口,这个服务的应用很灵活,因为厂家可以根据自己的需要为ECU定义各种各样的内部操作,而要执行这些操作只需要调用31服务就好了。典型的用途包括检查边界条件、清除闪存、对数据进行较验、对软硬件依赖性进行校验等,甚至有需要的话可以进行恢复出厂设置的操作,还有很多与ECU自身逻辑功能相关的操作也可以定义。
31命令的格式2F命令的格式
31服务的request由4部分组成
- SID
- sub-function,用于标识要执行什么动作,启动(0x01)、停止(0x02)、查询结果(0x03)
- routineIdentifier,用于标识要执行的routine
- routineControlOptionRecord,这是一个可选参数,用于标识routine执行时所需要的参数,由各家自定义它的内容
举个例子,假设用0x0809这个ID来代表检查ECU是否满足软件刷写条件(比如车速、转速为0,KL15接通等)的routine。
tester发送31 01 08 09来启动0x0809这个routine
如果所有条件都满足,则ECU返回71 01 08 09作为echo即可,如果条件不满足,则ECU返回71 01 08 09 XX YY ZZ,后边的XX YY ZZ则表明哪些条件不满足,具体的内容就由厂家自己定义了。
在关于UDS的第二篇文章中,我提到过UDS定义的服务从逻辑上分为6类,在第二至第六篇中已经讲解了前五类,在本文中将介绍最后一类UDS服务,即Upload Download functional unit ,数据的上传下载。
从成本等角度考虑,汽车ECU中用于缓存诊断服务数据的buffer大小有限,所以当我们需要读取或写入超过buffer大小的数据时,就无法简单地使用2E和22服务了,UDS据此定义了几个将大块数据写入或读出的服务,即数据下载和上传。
Upload Download functional unit总共定义了5个诊断服务,分别是:
- RequestDownload (0x34):客户端向服务器请求下载数据
- RequestUpload (0x35)客户端向服务器请求上传数据
- TransferData(0x36) 客户端向服务器传数据(下载),或者服务器向客户端传数据(上传)
- RequestTransferExit(0x37)数据传输完成,请求退出
- RequestFileTransfer(0x38) 传输文件的操作,可以用于替代上传下载的服务。
下图是数据下载的简略过程,用到了34,36,37这三个服务,如果是上传的话,34服务被35服务替换,数据传输方向变一下,就可以了。
Tester向ECU刷写数据的大概过程
RequestDownload (0x34)
0x34服务用于启动下载传输,作用是告知ECU准备接受数据,ECU则通过0x74 response告诉诊断仪自己是否允许传输,以及自己的接受能力是多大。
0x34服务的请求格式
0x34服务的请求格式包括5个部分
第一部分:1个byte的SID
第二部分:1个byte的dataFormatIdentifier,这里面标识了数据格式相关的信息,比如数据是否有压缩,是否有加密,用的什么算法加密等,应该由主机厂与供应商约定好,用哪个bit来表示压缩、加密等信息。
第三部分:1个字节的addressAndLengthFormatIdentifier,用于指示后面两个部分所占用的字节,高4bit表示memorySize所占的字节长度,低4bit表示memoryAddress
所占的字节长度。在这个例子中我将这两个值分别设置为n和m。
第四部分:m个字节的memoryAddress,由addressAndLengthFormatIdentifier中的低4bit指示。含义是要写入数据在ECU中的逻辑地址。
第五部分:n个字节的memorySize,由addressAndLengthFormatIdentifier中的高4bit指示。含义是要写入数据的字节数。
ECU收到请求之后,如果允许传输的话,会给出如下response
0x34服务的响应格式
第一部分:1个byte的 Response SID
第二部分:1个byte的dataFormatIdentifier作为echo
第三部分:maxNumberOfBlockLength,长度不定,表示可以通过0x36服务一次传输的最大数据量。
TransferData(0x36):
如果34服务得到了正确响应,tester就要启动数据传输过程了,使用的就是36服务。36服务的格式如下。
0x36服务的请求格式
第一部分:1个byte的 SID
第二部分:1个byte的blockSequenceCounter,标识当前传输的是第几个数据块,或者简单地说就是第几次调用36服务。
第三部分:transferRequestParameterRecord,传输的数据。第次传输数据量的上限就是34服务响应中的maxNumberOfBlockLength。
举例:如果ECU告知tester,maxNumberOfBlockLength = 20,也就是说tester每次通过36服务只能发送最多20个字节,其中还包括了SID和blockSequenceCounter,所以实际上每次可传的数据信息只有18个字节。如果tester要传的数据为50个字节,则需要传输三次,每次分别传输18,18,14个字节,即调用3次36服务。
36的响应很简单,就是一个字节的Response SID再加一个字节的blockSequenceCounter作为echo。
RequestTransferExit(0x37):
37服务用于退出上传下载,如果之前的34和36服务都顺利执行完成,那么37服务就可以得到ECU的positive response。
格式很简单,请求就是37,正确响应就是77,都是一个字节。
如果前面的36服务没有执行完成,以我前面举的例子来说,比如这个数据块有50个字节,但是tester只发了两次36服务传了36个字节,那么这次传输对于ECU来说是失败的,所以ECU应该给出NRC 0x7F 37 24,表示诊断序列执行有错误。
关于UDS所定义的诊断服务到这里就写完了。接下来我会写两篇文章补充一下UDS系列,分别介绍一下DTC的8个状态位的逻辑关系以及向ECU刷写数据或软件的完整流程。在此之后我会写几篇文章来讲述UDS在CAN总线上的实现,即所谓的UDSonCAN,涉及到TP层的分包、流控制、错误识别等内容,还有基于CAN实现的UDS中涉及到的各种时间参数。感兴趣的话可以继续关注。