黄利权,赵治国
(同济大学 汽车学院,上海 201804)
当今汽车因装配诸多的电控单元(electric control unit, ECU)而带来的电控系统维修困难,而汽车故障诊断仪则用于检测汽车上安装的ECU出现各种软、硬件故障,故障诊断仪和汽车上各个ECU的诊断模块进行通信,读取ECU记录的各种故障数据和内容信息,控制ECU完成特定的动作测试程序。现有的开发平台通过以下两种形式来调试和验证各种诊断数据的正确性:(1)手持式诊断仪和PC机上的ECU软件模拟器进行通信;(2)手持式诊断仪和实验室内台架上的ECU软件模拟器进行通信。因为这两种开发模式需要操作手持式诊断仪,而当诊断内容开发工程师在处理数量巨大的诊断数据时,繁琐且慢速的仪器操作会导致开发效率的低下,需要设计可以在同一台PC机上运行故障诊断软件和ECU模拟器的解决方案,通过该ECU模拟器可以对故障诊断仪进行诊断数据的离线仿真。
另外,根据ISO15765规范,PC机上的应用软件可以利用J2534 API作为访问Pass-thru(故障诊断仪在PC机上的工作模块,在本文中代表了在PC机上运行的诊断软件)设备驱动程序的接口。该协议包括J2534-1、J2534-2和J2534-3等3个部分。其中J2534-1定义了用于对发动机电控单元排放相关模块再编程的API接口,这些接口不仅可以用于再编程,也可以用于其他的功能目标[1]。通过这些API接口应用程序可以控制Pass-thru设备,也可以控制Pass-thru设备和车辆之间的通信。Pass-thru设备不需要解释所传输消息的内容,它允许任何的消息策略和消息结构被使用,只要它们能够被应用程序和ECU所理解。J2534相关的API接口类型如下:通信建立和断开,消息读写,启动和停止周期性消息,设置可编程电压,启动和关闭消息过滤器,读取版本信息和取得Last Error等操作[2]。
为了测试特定车型的诊断数据,笔者进一步开发了同样能在PC机上运行的ECU模拟器,只需在配置文件中修改虚拟ECU的诊断数据,就可以在诊断仪和ECU之间建立通信,实现在一台电脑上通过J2534诊断协议来完成故障诊断的数据验证。
ECU模拟器模块如图1所示。
图1 ECU模拟器模块
ECU模拟器包括MainExcutable、Core和J2534InjectDll 3个模块。各模块功能如下:
(1)MainExcutable模块把操作接口和高级功能提供给了用户,并在Core模块提供功能的基础上升级而成;
(2)Core模块完成了主要的接口模拟工作,处理来自于MainExcutable和J2534InjectDll的请求;
(3)J2534InjectDll模块把来自于故障诊断仪的调用推送给Core,并把来自于Core的响应推送给故障诊断仪。
模块结构图如图2所示。
图2 模块结构图
模拟器操作界面模块UI分别调用了Log模块、Vehicle模块和高级DataView修改模块,用于显示和编辑诊断通信数据。而J2534模块则通过Vehicle模块取得车辆诊断协议配置信息和ECU相关的诊断模拟数据,用于和故障诊断仪的相应API接口通信。
J2534Inject.dll模块经过Windows操作系统注册后就能够被J2534应用程序所识别。J2534应用程序首先加载J2534Inject.dll,然后映射到它自己的地址空间,最后调用J2534Inject.dll中的J2534接口函数来完成诊断通信。
模拟器接口方案采用的双进程模型如图3所示。
图3 双进程模型
其把模拟器从J2534应用程序中隔离出来。J2534Inject.dll驻留在以J2534为基础的诊断软件中,模拟器有它独立的进程。两个进程通过Windows RPC进行信息交换。
模拟器模块运行成一个独立的进程,并构建了J2534Inject.dll用于提供J2534接口,因为该DLL在故障诊断仪的上下文中运行,需要使用IPC(进程间数据交换)通信机制,当前IPC没有选择共享内存机制,而是使用了基于RPC(远程过程调用,即两个程序间通过传输协议进行通信)的IPC[3]。本研究采用该机制使得开发更容易,不需要担心进程间通信的技术问题,而是让操作系统来完成该项工作,开发人员只需要把它视为本地调用即可。另外当通信发生在相同的物理机器上时,RPC可以通过配置来使用LPC(本地过程调用)方法完成消息推送。
传统的ECU模拟器方案中手持式诊断仪和PC机上的ECU软件模拟器进行通信,有如下的缺点:手持式诊断仪在操作时数据显示有一定延迟,且诊断内容开发工程师需要在仪器和PC机电脑之间反复切换操作,另外ECU模拟器和手持式诊断仪之间的通信需要有接线盒以及USB转接板等设备,在调试时有时会因为通信链路存在问题而需要排查原因。而采用了J2534诊断协议后,则可以完全避免以上问题。同时也可以通过开发脚本程序把诊断数据按照指定格式直接转化为该ECU模拟器的数据配置文件,用于诊断通信。
软件模拟器UML用例图如图4所示。
图4 UML用例图
诊断应用角色代表了诊断仪,而用户角色则代表了ECU模拟器操作者。诊断仪中的“J2534通信”用例和“车辆协议模拟”用例通过IPC机制进行通信。同时模拟器的功能用例(整帧匹配、数据浏览和修改和消息日志)是依赖于“车辆协议模拟”用例来实现的。而“整帧匹配功能”用例则将匹配结果反馈给模拟器操作者。最后“配置”用例不同,则“车辆协议模拟”用例对应不同的诊断协议,即向操作者提供不同的协议模拟功能。
用例向诊断工具提供了一个含有J2534接口的J2534Inject.dll。诊断工具加载该DLL,并通过它和模拟器进行通信。J2534Inject.dll必须遵循J2534标准。
因为该模拟器和J2534Inject.dll并不在同一个进程中,必须有一种机制来完成模拟器和该DLL之间的IPC通信。IPC机制使得诊断工具可以像调用自己的内部函数一样调用程序。
因为类J2534RpcInvoker包含在J2534InjectDll里,含有该类的文件应该被加入J2534InjectDll的工程,而其他类属于Core工程。
J2534软件包中的诊断仪接口需要遵循J2534标准。该软件包包含了用于通信的车辆程序接口和由诊断仪引发的J2534工作日志。
J2534类图如图5所示。
图5 J2534类图
其中,通信信道管理器CJChannelMgr中包含了多个信道CJChannel,而每个信道则由若干个消息滤波管理器CJMsgFilterMgr所组成。同时每个信道CJChannel依赖于带有垃圾回收功能的总线节点类CBusNode,总线节点是由相关诊断协议栈构成,而协议栈中不同层(物理层、数据链路层、网络层和应用层)由不同类型的诊断协议所组合而成[4]。另外CJChannel则负责主要的J2534通信,即负责收发消息并调用消息过滤管理器。它把类似J2534协议的请求转化为了内部的一些协议和数据组织方式。设备管理器CJDeviceMgr由多个CJDevice所组成,CJDevice目前主要代表了故障诊断仪模型,它记录了引脚和相关的电压信息。
CJMediator继承自J2534Invoker,实现了J2534协议中包含的API接口,并且负责调度消息滤波管理器CJMsgFilterMgr,信道CJChannel,设备管理器CJDeviceMgr和设备CJDevice。
J2534序列图如图6所示。
图6 J2534序列图
当诊断应用发起一个设备相关的调用时,完成如下工作:
(1)在J2534InjectDll中,J2534接口的调用工作将被派遣给J2534RpcInvoker,它也有类似于J2534的成员函数;
(2)J2534RpcInvoker封装了诊断应用发过来的参数,然后再发送给RPC接口;
(3)在模拟器的处理流程中,当接收到一个来自于RPC客户端的消息时,类RpcServer代表的监听线程将被唤醒用于处理RPC调用;
(4)RpcServer拆开接收到的参数,然后把它们转发给含有类似于J2534协议相关成员函数的CJMediator;
(5)CJMediator解释了J2534协议相关的接口并调用了CJChannel和CJDevice实例提供的方法,如果需要创建一个新的实例,或者需要释放一个已经存在的实例,那么CJMediator将指示CJDeviceMgr和CJChannelMgr分别完成或释放此类任务;
(6)在处理来自J2534协议相关接口的请求后,调用流程将逆向进行,参数需要被返回,并且函数的返回值需要被封装,最后需要由RpcServer和J2534RpcInvoker完成拆解;
(7)负责RPC通信机制的类J2534RpcInvoker包含于J2534InjectDLL,其他则包含在Core模块里。
Vehicle类属于Core工程,类中的CVehicle、CBusNode和CDiagProtocol将被本模块以外的软件包所引用。
Vehicle类图如图7所示。
图7 Vehicle类图
主要内容解释如下:
(1)核心的处理类是CVehicle,并通过它给出了CBus和CECU。一个CBus(即某个车型的总线)是由多个CBusNode实例组成,同时一个CECU是由于多个CDiagProtocol实例组成;
(2)CBusNode是J2534模块和Vehicle模块通信的桥梁;
(3)CDiagProtocol带有面向UI接口。
当J2534通道从RPC接收到消息时,它将把消息推送到关联在它身上的CBusNode上。
Vehicle消息处理时序过程如图8所示。
图8 Vehicle消息序列图
对于所有消息都按照如下过程处理:
(1)CJChannel把消息放置到挂在它上面的CBusNode上(通过调用J2534Node);
(2)J2534Node把消息从诊断协议栈上层传到底层(上层和底层根据ISO协议分层定义),每一个存在层均按照协议规范封装消息(通常添加了报文头和校验码),最后底层把消息传到总线上(CBus的实例);
(3)CBus把它缓冲里的消息推送到其他CBusNode实例(这里为EcuSysNode);
(4)当EcuSysNode的诊断协议栈底层接收到消息时,它把消息从底层往上层传递,每个协议栈中存在的协议层均按照协议解析消息(通常是远程报文头和校验码);
(5)如果一条消息能够在EcuSysNode的某一协议层中被处理,那么停止继续向上层传递消息,当前协议层将直接处理它并发送响应;如果消息不被诊断层以下的协议层处理,CDiagProtocol将接收下,并有机会去处理它。在处理后它会发送报文响应,响应消息的处理路径按从EcuSysNode到CBus,再到J2534Node,最后到CJChannel的流程运转。
协议栈每一层的命令处理流程如图9所示。
图9 每层中命令处理的活动图
整帧的匹配操作有着最高优先级,如果它在每个工作的层中被包含,那么对于接收到的每个消息,整帧将被首先进行匹配。如果该消息没有匹配已存在的任何命令,则该层将进行下面的协议处理,如果发现相应的响应报文,则发送响应报文。
CProtocolLayer类是消息的协议处理的基本定义,CProtocolLayer是一个抽象类,它没有任何实例,一些方法被定义成纯虚函数。
这些诊断协议类继承自CDiagProtocol,主要诊断协议子类型如表1所示。
表1 继承自CDiagProtocol类的诊断协议类
CHDC_CAN类—代表了ISO15765协议;CH9X类—代表了Honda系列协议;CKwp2000Diag类—代表了Keyword2000协议
本类继承自CProtocolLayer,主要成员函数如表2所示。
表2 CNodeLayer类的主要成员函数
(1)CNodeLayer的实例是在协议栈的各层中,它有一个可选的上、下层,根据ISO下层提供服务给上层,所以每个CNodeLayer实例都有一个处理它下层的句柄,SetLayerDown()方法是被用来设置此类句柄;
(2)CNodeLayerBottom和CNodeLayerTop继承自该类,它们组成了CBusNode中的协议栈里的各个诊断协议层,例如ISO/WD 15765协议则是基于CAN总线的Keyword2000协议,即该协议栈的数据链路层是ISO 11898-1 CAN协议,上层是由Keyword2000或UDS的应用层移植而成[5];
(3)UpdateSend()和UpdateRecv()在主循环中被用于消息处理;
(4)PutIntoTXBuf()和GetFromRXBuf()是用于推动消息传递;
(5)Configure()采用一个具体的配置类来完成参数配置、定义和检查配置参数的有效性。
CIso15765_2Layer和CKwp2000DLLayer两个类继承自CNodeLayer。
CIso15765_2Layer是ISO15765协议的网络层。ISO/DIS 15765:1999年出台ISO/DIS 15765(Diagnostics on CAN-based on KWP2000),该诊断标准是基于ISO 14230在CAN线上的扩充,源于K线的诊断标准。其基本原理是把KWP2000的应用层诊断服务移植到CAN总线,它的数据链路层采用ISO 11898-1[6]。
CKwp2000DLLayer是KWP2000的数据链路层。ISO 14230:ISO 14230于1999年出台,该诊断标准基于K线,波特率为10.4 kb/s,用单线(K线)通信,也可用双线(K线和L线)通信。ISO14230的头格式不是固定的,有3或4个字节,报文传输不用分包,最大可传255个字节数据,K线本质上是一种半双工串行通信总线[7]。
协议数据类型相关类是包含在命名空间ProtoDataType中,并且继承自CBaseMgr。它们被用来作为CDiagProtocol实例的扩展属性。包含CBaseMgr在内,都是派生自CGarbagable类。
继承自CBaseMgr类的协议数据类型如表3所示。
表3 继承自CBaseMgr类的协议数据类型
CUintData—用于无符号整形数值属性;CmdAndRes—用于整帧匹配;CDataList—用于诊断协议的数据模型
CMemBlock用于诊断协议的内存模型。
数据验证所使用的模拟器配置文件中A/C ECU的DID数值设置相关的版本信息部分如表4所示。
表4 模拟器配置文件中A/C ECU的DID数值设置——(读取版本信息)
数据验证所使用的模拟器配置文件中A/C ECU的DID数值设置相关的数据流部分如表5所示。
表5 模拟器配置文件中A/C ECU的DID数值设置——(读数据流)
模拟器端数据验证工作原理如下:ECU模拟器根据表4中的ECU版本信息构造相关的DID(数据标识符)版本数据,根据表5中的数据换算公式构造相关的DID数据,并把构造的测试数据写入它的诊断数据配置文件DVP(自定义的文件格式)中。在ECU模拟器和DiagAnalyzer进行诊断通信会话时,它将加载DVP文件中的诊断数据,通过故障诊断仪软件完成对ECU模拟器的测试。
诊断仪显示的A/C ECU的DID数值设置相关的版本信息部分如表6所示。
表6 诊断仪显示的A/C ECU的DID数值设置——(读取版本信息)
诊断仪显示的A/C ECU的DID数值设置相关的数据流部分如表7所示。
表7 诊断仪显示的A/C ECU的DID数值设置——(读数据流)
该ECU模拟器可以对所有采用了Keyword 2000和UDS诊断协议[8]的ECU进行诊断数据的仿真,同时为了充分验证程序的正确性,笔者采用了在北美地区销售的斯巴鲁某车型中的ECU集合进行了验证。测试DataManager所涉及的ECU集合如表8所示。
表8 测试DataManager所涉及的ECU集合
每个ECU所测试的内容包括:DID数值设置(ECU版本号,软硬件版本号等),显示数据流,读取和清除DTC故障码等项目。经过测试诊断结果显示内容与ECU模拟器中配置的故障码的故障描述及故障信息在个数和内容上完全一致,且诊断结果显示内容中的数据值不断刷新显示,即在执行中连续读取数据,诊断结果相对ECU配置的数据值具有较高的精确度,因此读取故障码诊断功能实现,且其诊断结果相对ECU模拟器的故障码和数据流更准确、可靠。
本研究开发了ECU模拟器及其与诊断仪通信接口,具有如下优点:通过该模拟器,开发工程师只要在软件的数据配置文件中根据故障诊断协议写入各种诊断数据,即可完成对特定车型诊断数据的开发和调试,只需要一台PC机就可以完成汽车上各个ECU的诊断数据开发;同时该ECU模拟器支持目前市场主流的故障诊断协议。另外,由于该ECU模拟器遵循J2534接口协议,可以和其他遵循该协议的故障诊断软件进行匹配和通信。
具体结论如下:
(1)该ECU模拟器支持UDS和Keyword2000等诊断协议,用户只需要按照指定格式修改DVP配置文件即可实现新ECU诊断数据的加载;
(2)通过使用J2534Inject.dll,可以在电脑平台上完成DiagAnalyzer故障诊断仪和ECU模拟器之间的诊断数据通信,省略了硬件转换模块;
(3)在模拟器的GUI操作界面上开发了多种数据展示和修改方式,可以提高工作效率;
(4)在一个被模拟的ECU上可以设置多个信号,并且给特定信号指定最大值、最小值、回包中所处的位置等。