文章包含了AUTOSAR基础软件(BSW)中DCM模块相关的内容详解。本文从ISO标准,AUTOSAR规范解析,ISOLAR-AB配置以及模块相关代码分析四个维度来帮读者清晰的认识和了解DCM这一基础软件模块。文中涉及的ISOLAR-AB配置以及模块相关代码都是依托于ETAS提供的工具链来配置与生成的,与AUTOSAR规范之间可能会有些许的出入,但总体的功能要点与处理流程都应该是一致的。
DCM模块是汽车诊断的一个部分,这个部分主要包含了基于AUTOSAR通信栈的报文处理以及会话和安全等级管理,标准的网络层和会话层以及部分应用层都在这里实现,包括DID的读取,写入,控制也在这里实现。文章首先介绍了何为诊断,其次以IOS-15765以及ISO-14229基础介绍了DCM涉及的部分标准,再次解析了AUTOSAR规范DCM部分内容,然后基于ISOLAR讲述了完整的DCM配置过程,最后介绍了DCM相关的代码。
目录
诊断概述
ISO-15765与ISO-14229
缩写与术语
网络层
应用层
10服务
11服务
27服务
28服务
3E服务
22服务
2E服务
2F服务
31服务
AUTOSAR规范解析
概述
总体设计元素
DCM子模块
否定响应码
非易失数据
Diagnostic Session Layer (DSL)
Diagnostic Service Dispatcher (DSD)
Diagnostic Service Processing (DSP)
ISOLAR-AB配置
导入诊断报文
DCM
DcmGeneral
DcmRbGeneral
DcmDslBuffer
DcmDslDiagResp
DcmDslProtocolRow
DcmDslMainConnection
DcmDslProtocolRx
DcmDslProtocolTx
DcmDsd
DcmDsdServiceTable
DcmDsp
DcmDspSecurity
DcmDspSecurityRow
DcmDspSession
DcmDspSessionRow
DcmDsdService
DcmDspComControlAllChannel
DcmDspCommonAuthorization
DcmDspData
DcmDspDidInfo
DcmDspDid
DcmDspRoutine
DcmPageBuffercfg
CanTp
CanTpGeneral
CanTpChannel
CanTpRxNSdu
CanTpTxNSdu
Components
System
RTE
代码解析
动态配置代码
集成代码
静态代码
诊断概述
汽车诊断的作用,就是在不对车进行进行解体的情况下,检查车的状况,如果有故障则可以通过汽车诊断来查明故障部位及原因。具体的操作过程需要通过诊断仪连接到汽车的OBD口读取车况信息,下图为博世的一款诊断仪。
诊断仪的另一端连接汽车的OBD口,一般在主驾的膝盖位置。
下图为OBD的引脚定义。
完成诊断仪和汽车的连接之后,检修人员就能够在诊断仪的屏幕获取车辆的数据信息,诊断仪和汽车之间的通信遵循特定的通信协议,针对OSI(Open System Interconnect)七层模型,诊断协议标准分别定义了各层实现的相关内容。
本文介绍的是UDS on CAN的诊断协议,也就是说物理层和数据链路层都是CAN,可以看到诊断也可以基于LIN或者FlexRay等物理链路层来实现,本文不介绍物理层和数据链路层的具体实现,着眼介绍在CAN总线上发生的诊断活动。
诊断协议对数据链路层会建议对于CAN帧中未使用字节通过某个特定值如0xAA进行填充,防止连续传输相同比特值导致的位填充。
ISO-15765与ISO-14229
缩写与术语
- ECU:Electronic Control Unit,电子控制单元。
- ISO:International Standards Organization,国际标准组织。
- EOL:End Of Line,产品下线。
- SF_DL:Single Frame Data Length,单帧数据长度。
- FF_DL:First Frame Data Length,第一帧数据长度。
- SN:Sequence Number,帧序号。
- FS:Flow Status,流控制状态。
- BS:Block Size,块大小。
- STmin:Minimum Separation Time,最小连续帧时间。
- SID:Service Identifier,服务标识符。
- DTC:Diagnostic Trouble Code,故障诊断码。
- DID:Data Identifier,数据标识符。
- NRC:Negative Response Code,否定影响标识符。
网络层
下图示意诊断仪连接到汽车。
由上图可以看出,诊断仪为客户端,汽车(ECUs)为服务端。诊断仪发起请求,ECUs回复。这里就有有一个问题,汽车上有很多ECU都挂接到了一个CAN线上,怎么区分诊断仪请求的ECU是哪个?UDS on CAN通过CAN帧的帧ID来区分,Physical Request CAN ID(物理寻址)的请求针对的是某个具体的ECU,Functional Request CAN ID(功能寻址)的请求则针对某一类ECUs。很多UDS服务只支持物理寻址,功能寻址并不能访问。
经典CAN有8个字节,每一帧最大只能传输8个字节的数据,上层网络要想通过CAN帧来传递信息就会出现两种情况,有些消息长度很短,只需要CAN的一帧就可以解决;而有些消息长度很大,无法通过CAN的一帧来完整传输,那么就需要将该消息按照一定规则进行分割成若干个CAN帧进行传输。ISO15765-2为实现上一目标将CAN帧分成了以下四种类型。
- SingleFrame (SF):单帧,第一个字节的高四位为0,低四位为接下来要传输的数据长度,后7个字节为要传输的数据。
- FirstFrame (FF):首帧,第一个字节的高四位为1,第一个字节低四位与第二个字节合起来为接下来连续帧要传输的数据长度,从第三个字节byte2至最后一个字节byte7为首帧传输数据。
- ConsecutiveFrame(CF):连续帧,第一个字节的高四位为2,第一个字节的低四位为连续帧编号(SN),表示当前连续帧的顺序,第一条连续帧的SN=1,后面每发出一帧连续帧SN加1,范围0~15,当SN=15时,下一条连续帧重新变成0。第二个字节byte1至最后一个字节byte7为剩余的数据。首帧已经传输了6个字节,则接下来就是通过连续帧继续传输剩下的数据。
- FlowControl (FC):流控帧,第一个字节高四位为3,低四位为FlowSttatus(FS),第一个字节为BlockSize(BS),第二个字节为SeparationTimeMin(STmin),作用在于接收端告知发送端接收能力。
- FS:0代表继续发送连续帧,1代表等待下一帧流控帧,3代表首帧说明的数据大小溢出。
- BS:0代表发送端可以一致发送至数据发完,不必再等待流控帧,01~FF指示这个流控帧生效的连续帧数,发送端应发送完对应数量的连续帧之后等待新的流控帧。
- STmin:表示发送端发送连续帧的最小间隔时间,00~7F,对应范围为0ms~127ms;F1~F9,对应范围为100us~900us。
单帧的发送过程比较简单,下图示例发送数据0x01~0x07到接收端的CAN帧数据。
多帧的发送过程就比较复杂了,如下图所示,是发送端利用多帧发送数据0x01~0x24,可以看出接收端通过流控帧实现了不同Block,不同STmin。
ISO15765-2中还针对时间制定了严格的超时机制,在网络层中主要有如下几个时间参数:
- N_As:发送端发送一条CAN消息的时间。
- N_Ar:接收端发送一条CAN消息的时间。
- N_Bs:发送端发送首帧后到接受到流控帧的时间。
- N_Br:接收端收到首帧后到发送流控帧的时间。
- N_Cs:发送端收到流控帧后到发送连续帧的时间。
- N_Cr:接收端收下一个连续帧的时间。
应用层
UDS协议是一种服务器-客户端交互模式,发送端发送请求,接收端返回响应。为了来实现这种通话模式,网络层负责的是数据的传输,而应用层则考虑的是服务的定义,所以ISO14229-1主要规定诊断服务定义以及应用层层面的超时控制。下面是应用层超时控制涉及的参数。
- P2Client和P2Server是诊断仪(Tester)诊断请求与ECU响应间的时间间隔。
- P2Client:在Tester成功发送诊断请求后等待ECU发送响应的超时时间,针对的是上位机Tester端。
- P2Server:是ECU收到Tester请求报文后到发出响应的时间间隔,针对的是ECU端。
- P2*Client与P2*Server是Tester收到否定应答NRC为78h的否定应答报文后等待的增强超时时间。
- P2*Client:Tester在接收到ECU应答的NRC为0x78时,到收到ECU响应的单帧或首帧的超时时间,在收到0x78的NRC时,Tester将重置定时器到新的增强超时时间。
- P2*Server:在ECU发出NRC为0x78的响应后,到ECU开始答复请求的时间要求,即需要在该时间段内响应上位机请求或再次发送0x78的NRC,再次重新计时。
- P3Client_Phys与P3Client_Func诊断仪连续请求的时间间隔。
- P3Client_Phys:Tester从成功发送物理寻址开始计时到下一次发送物理寻址的时间间隔 ,一般为P2Server_max。
- P3Client_Func:Tester从成功发送功能寻址开始计时到下一次发送物理寻址的时间间隔 ,一般为P2Server_max。
- S3Client与S3Server。
- S3Client:发送下个TesterPresent(0x3E)以保持在非默认会话模式的时间。
- S3Server:保持在非默认会话下的超时时间,超时后返回默认会话模式 。
UDS定义的诊断服务如下表所示。
下面针对后边涉及的相关诊断服务,进行说明。这里介绍的诊断服务是除了Boot升级程序以及DTC故障码相关的服务,这两类服务会在介绍Boot以及DEM模块时再具体讲解。
10服务
10服务用于控制诊断会话状态,不同的会话状态对应不同的服务访问权限,比如28服务在Default会话一般不能访问。
下图是三种模式之间的切换的示意图。可以看到编程模式没有切换到别的模式路径,一般切换到编程模式之后要不重新刷写程序重启,要么从Boot跳转APP重新初始化了DCM。
下图是两个10服务的实例,首先Tester发送了10 01,10是服务号,01是子功能,表示切换到默认会话。02为编程会话,如果ECU要做在线升级,那么首先就要切换到编程会话,03为扩展会话,这个会话一般会放一些读写数据或者控制外围设备的操作。
ECU回复报文50 01 00 32 01 F4,首先,50是10+0x40后的响应,所有服务的ID响应报文都是服务ID+0x40,01是对应的请求子服务,00 32和01 F4是P2Server_max和P2*Server_max,用于告知Tester其网络层能力。
下面这个是Tester发送错误请求的例子,它请求了错误的66子服务,ECU不认识,回复了7F 10 12,7F是否定响应服务标识符,表示回复的是一个否定响应,10是否定响应的请求ID,12为否定响应标识符(NRC)。
服务涉及的NRC标识符含义如下,可以看到0x12为子服务不支持。
11服务
11服务是重启的服务,诊断仪可以通过这个服务要求ECU重启,11服务也是有子功能的,如下图。
重启的具体行为需要上层应用决定,DCM在收到复位指令之后会根据子服务调用不同的上层实现,可以是看门狗复位,也可以是芯片自身提供的复位指令,也可以是电源断电复位。下图为实例。
可以看到诊断仪给Tester发送了02 11 01,其中02表示的是单帧+数据长度。11 01为对应的服务和子服务信息。诊断仪恢复了02 51 01,51 01即为11 01的正响应。
下图是长度不正确的实例。可以看到回复的NRC为13。
下面是11的NRC说明。
27服务
安全访问服务,这个服务用于在修改ECU关键参数和升级的时候使用,比如写汽车的VIN码之前。下图为子服务说明,ECU一般涉及两个安全等级,安全等级1一般用于应用程序运行时修改关键参数,安全等级3用于升级程序。
下图为实例, 可以看到Tester发送10 03首先进入扩展会话,ECU回复正响应之后,Tester发送27 01请求安全等级为1的种子,ECU回复的Seed为03 04 0A 01,然后Tester拿到种子经过计算之后发送密钥给ECU,如果密钥正确,则会回复正响应67 02。
下图是涉及的否定响应码,可以看到如果在接收到请求密钥子功能前没有先接收到请求种子报文,发送24。如果接收到密钥值与ECU内部存储或计算的密钥不相等,发送35。
28服务
通信控制服务,涉及的子服务如下图。它们用于使能和禁止通信。
28服务在子服务后边还会跟一个字节指示对应的控制通信的类型,可以看到控制的通信都是应用层以及网络管理报文,底层涉及通信的模块(XCP、DCM)还能正常。
下图为28服务的实例。首先Tester发送10 03进入扩展会话,然后发送28 00 03 能够使能应用和网络管理的报文发送与接收,而后又发送28 03 03,禁用了应用和网络管理的报文发送与接收。这个服务可以帮助我们在调试时,排除一些干扰报文。
下图为28服务涉及的NRC。
3E服务
诊断仪在线服务,主要目的就是告知ECU,诊断仪正在与ECU连接,因为ECU在非默认会话的时候,内部有计数器,超时就会跳回到默认会话中,如果诊断仪以小于超时时间为周期发送3E,则会让ECU维持在当前的会话状态。下图为对应的子服务。
下图为具体的3E服务实例。
22服务
DataByldentifier简称DID,意思为用一个数字标识的数据,22服务下可以访问众多用户自定义的DID。比如0xF190对应的是VIN码,ISO 14229-1定义了一些DID,当然,主机厂可以根据自己的情况自定义。
22服务没有子服务,下面是22服务的一个实例。读取的DID为FA 00,读取到的数据为03。
22服务支持的NRC如下。
2E服务
22服务是读DID,2E服务是写DID。2E服务没有子服务,下面是一个具体的实例,DID为F1 99 写入01 02 03,使用22服务读取的结果也是01 02 03。
服务支持的NRC有:
2F服务
2F服务是用来完成输入输出控制,他也是通过DID来区分要控制的东西。这个命令可以在DV实验或者ECU已经上车之后,需要测试某个具体的功能,不方便使用调试器等工具了,就可以使用这个服务。2F服务没有子功能。
下面是2F服务的一个实例,Tester首先发送10 03进入扩展会话,然后2F服务访问F0 13这个DID,参数是03 00 00。ECU接收到这个命令,首先解析DID,然后获取参数,进行对应的输入输出控制,下面的例子ECU返回了个不支持这个DID的负响应,正响应应该是6F F0 13。
下面是该服务支持的NRC。
31服务
31服务是例程控制,主机厂可以利用这个服务完成EOL的某些功能,包括下线标定,校准,钥匙配对等动作。下面是服务涉及的子服务。
下图为ISO 14229-1对这三个子服务的解释。
下图是32服务的实例,先使用10 03进入扩展会话,然后使用31 01启动FF 01对应的例程,下面的例子ECU回复了NRC为33的负响应,正响应应该为71 01 FF 01 00。其中最后的字节00为制造商自定义的ECU返回的一些附加信息。
AUTOSAR规范解析
概述
Dcm规范描述了AUTOSAR基本软件模块Dcm(Diagnostic Communication Manager)的功能API和配置。Dcm模块为诊断服务提供了通用API。DCM模块的功能在开发、制造或服务过程中由外部诊断工具(诊断仪)使用。
Dcm模块确保诊断数据流和管理诊断状态,特别是诊断会话和安全状态。此外,DCM模块根据诊断状态检查是否支持诊断服务请求以及是否可以在当前会话中执行服务。
在AUTOSAR体系结构中,诊断通信管理器位于通信服务(服务层)中。
Dcm模块与通信无关。所有通信特定功能(如CAN、LIN、FlexRay或MOST等通信的实现)都在Dcm模块之外处理。PDU路由器(PDUR)模块为Dcm模块提供了与网络无关的接口。Dcm模块接收来自PduR模块的诊断消息。Dcm模块在内部处理和检查诊断消息。作为处理诊断请求的一部分,DCM将与其他BSW模块或SW-Components(通过RTE)交互以获取请求的数据或执行请求的命令。这种处理是非常特定于服务的。通常,Dcm将收集到的信息集合起来,并通过PduR模块发送回消息。
总体设计元素
DCM子模块
为了定义Dcm模块的功能,AUTISAR将Dcm模块建模为由以下子块组成:
- 诊断会话层(Diagnostic Session Layer,DSL)子模块:DSL子模块确保与诊断请求和响应有关的数据流,监督和保证诊断协议的时序,管理诊断状态(特别是诊断会话和安全)。
- 诊断服务分派器(Diagnostic Service Dispatcher,DSD)子模块:DSD子模块处理诊断数据流:
- 通过network接收新的诊断请求,并将其转发给数据处理器。
- 当由数据处理器(DSP子模块)触发时,通过network传输诊断响应报文。
- 诊断服务处理(Diagnostic Service Processing DSP)子模块:DSP子模块处理实际的诊断服务(各自的子服务)请求。
下图概述了Dcm模块中的子模块DSP、DSD和DSL之间以及对外模块的接口。注意这些子模块的实现和它们之间的接口不是强制性的。引入它们只是为了提高此规范的可读性。
否定响应码
ISO标准规定了UDS服务和OBD服务的负响应代码(NRC)。DcmSWS在Dcm和其他BSW模块以及SW-Cs之间的接口中使用这些NRC。这些NRC是在数据类型DcmNegativeResponseCodeType中定义的。
非易失数据
Dcm的几个特性需要初始化非易失性信息。AUTOSAR没有说明如何访问这些信息,或者在Dcm初始化时这些信息是否已经可用。因此,对非易失性信息的访问是实现的具体问题,必须在集成过程中加以确保。
Diagnostic Session Layer (DSL)
DSL子模块的所有功能应符合ISO14229-1规范和与网络无关的IS015765-3规范部分。 DSL子模块提供以下功能:
- 会话控制(符合ISO14229-1与ISO 15765-3 [4]标准)。
- 应用层时序处理(符合ISO14229-1与ISO 15765-3 [4]标准)。
- 诊断相应行为的实现(符合ISO14229-1与ISO 15765-3 [4]标准)。
- 每个诊断连接的安全验证状态处理。
- 为每个连接提供安全验证状态管理。
- 管理安全验证状态转换。
DSL与其他模块有以下交互:
- PduR module
- PDUR模块提供传入诊断请求的数据。
- DSL子模块触发诊断响应的输出。
- DSD submodule
- DSD子模块将传入请求通知DsD子模块并提供数据。
- DSD子模块触发诊断响应输出。
- SW-Cs / DSP子模块
- DSL子模块提供对安全性和会话状态的访问。
- ComM module
- DSL子模块保证ComM模块所需的通信行为。
Diagnostic Service Dispatcher (DSD)
DSD子模块负责检查传入诊断请求的有效性(诊断会话/安全访问级别/应用许可的验证),并跟踪服务请求执行的进度。处理有效的请求并拒绝无效的请求。子模块涉及以下相关用例:
- 接收请求消息并传送正响应消息:这是正常通信(“乒乓”)的标准用例。服务器接收诊断请求消息。DSD子模块保证了请求消息的有效性。在这个用例中,请求是有效的,响应将是肯定的。请求将被转发到DSP子模块中相应的数据处理器。当数据处理器完成所有数据处理操作后,它触发由DSD子模块发送响应消息。
- 接收请求消息并且抑制正响应:这是前一个用例的子用例。在UDS协议中,可以通过在请求消息中设置一个特殊位来抑制正响应。这种特殊的抑制处理完全在DSD子模块中执行。
- 接收请求消息且抑制负响应:在功能寻址的情况下,DSD子模块应抑制NRC0x11、0x12、0x31、0x7E和0x7F。
- 接收请求消息并且传送负响应消息:拒绝请求消息和发送否定响应有许多不同的原因。如果诊断请求无效或在当前会话中可能无法执行请求,则DSD子模块将拒绝请求并返回否定的响应。DSP子模块将触发一个负响应,其中包括一个NRC,该NRC将提供更多信息,说明为什么该请求被拒绝。
- 直接发送肯定响应消息:UDS协议中有两个服务,一个请求发送可能会对应多个响应。这些服务是:
- ReadDataByPeriodicIdentifier (0x2A): 此服务允许客户端请求从服务器定期传输一个或多个periodicDataIdentifiers.。
- ResponseOnEvent (0x86):此服务请求服务器启动或停止传输对指定事件的响应。
- 分段响应:在诊断方案中,一些服务允许交换大量的数据,例如UDS服务读取DTC信息(0x19)和UDS服务传输数据(0x36)。在传统方法中,ECU内部缓冲区必须足够大,以保存要交换的最长数据消息(最坏的情况),并且在启动传输之前填充完整的缓冲区。ECU中的RAM存储器通常是一个关键资源,特别是在较小的微处理器中。在更节省内存的方法中,缓冲区只被部分填充,部分传输,然后部分重新填充,依此类推。这种分页机制只需要显著的内存量,但需要一个定义明确的缓冲区重新填充的反应时间。用户可以决定是使用linear buffer或者paged-buffer。当接收到诊断消息时,DSL子模块调用DSD子模块。DSD子模块执行以下操作:
- 将请求的处理委托给DSP子模块或Dcm外的外部模块跟踪请求处理。
- 跟踪请求处理,处理处理函数的返回状态。
- 将诊断的响应传输到DSL子模块(传输功能性)。
最后总结一下DSD与DSL的主要功能交互:
- DSD子模块到DSL子模块:获取当前的诊断会话和安全级别。
- DSL子模块到DSD子模块:诊断信息传输的确认。
DSD与DSP的主要功能交互如下:
- DSD子模块到DSP子模块:委托处理请求与诊断信息传输确认。
- DSP子模块到DSD子模块:发出信号表示处理已完成。
Diagnostic Service Processing (DSP)
当从DSD子模块接收到要求DSP子模块处理诊断服务请求的函数调用时,DSP始终执行以下基本处理步骤:
- 分析接收到的请求消息。
- 检查格式以及是否支持寻址子函数。
- 在DEM、SW-Cs或其他BSW模块上获取数据或执行所需的函数。
- 构建服务响应
DSP子模块将在执行所请求的命令之前检查适当的消息长度和结构。当对请求消息的分析导致格式化或长度错误时,DSP子模块应触发NRC0x13(错误消息长度或无效格式)的负响应。
DSP子模块应根据响应服务标识符构建响应消息并确定响应消息长度。
除非指定了另一个特定NRC,否则当执行服务的API调用未返回OK时,DSP子模块应触发NRC0x10(一般拒绝)的负响应。当对请求消息的分析导致出现其他不支持的消息参数时,DSP子模块应触发NRC0x31(请求超出范围)的负响应。
ISOLAR-AB配置
导入诊断报文
导入诊断报文如下图所示。
点击 导入DBC,如下图所示两收一发。
之后使用RTA-BSW下的Automatically Configure BSW from System Description生成通信栈相关配置之后,就可以在配置DSL时引用到相关报文。
DCM
DcmGeneral
这个容器配置的是一些DCM的通用配置,如下图所示。
DcmRbGeneral
该容器需要关心的配置如下:
- DcmRbsuppressNRC:此参数用于配置当诊断请0求收到时,支持回复的NRC值。下图实例中配置了:
- 11:服务不支持。
- 12:子服务不支持。
- 31:请求报文中包含的参数值超出了授权范围。
- 7E:ECU在当前的会话模式下不支持请求的子服务,所以请求的动作不能被执行。
- 7F:ECU在当前的会话模式下不支持请求的服务,所以请求的动作不能被执行。
- DcmRbconfirmForDSDGeneratedNegRes:如果设置为真,DSD在产生否定响应的时候会调用DcmAppl_DcmConfirmation DcmNegResp()来进行确认。
- DcmRbosTimerUse:DCM内部Timer的节拍来源,实例中选择CyclicCount,则节拍来自Dcm_mainfunction的调用周期,计时原理为调用次数*调用周期。
- DcmRbRTEsupport: 如果参数为真,通信管理,诊断会话控制以及ECU重启相关的Ports会被生成。
- DcmRbStoringEnabled:使能存储诊断信息(跳转到Boot)。
DcmDslBuffer
建立两个DslBuffer,一个用于发送,另一个用于接收,大小为1024Bytes。
DcmDslDiagResp
设置针对每个诊断请求,最大的0x78否定响应(ECU正忙,未准备好接收此请求),超过此限制将回复0x10否定响应(拒绝执行请求)。
DcmDslProtocolRow
该容器包含一种诊断协议的参数配置,主要的配置如下:
- DcmDslProtocollD:诊断协议选择,下面的实例选择的是UDS_ON_CAN,还可以根据需要选择OBD_ON_CAN以及UDS_ON_IP等。
- DcmDslProtocolPriority:用作协议抢占优先级配置,0是最高优先级。
- DcmTimStrP2ServerAdjust:前文提到的P2Server超时时间。
- DcmTimStrP2StarServerAdjust:前文提到的P2*Server超时时间。
- DcmDslProtocolRxBufferRef:协议接收Buffer,引用在DcmDslBuffer处定义的接收Buffer。
- DcmDslProtocolSlDTable:协议涉及的服务列表,引用在DcmDsdServiceTable处定义的。
- DcmDslProtocolTxBufferRef:协议发送Buffer,引用在DcmDslBuffer处定义的发送Buffer。
DcmDslMainConnection
DSL与通信的连接信息,它引用的是之前将诊断报文导入的CAN控制器。
DcmDslProtocolRx
引用物理以及功能寻址两个PduR2Dcm,连接到当前的诊断协议中。
DcmDslProtocolTx
引用ECU诊断回复的PduR2Dcm,连接到当前的诊断协议中。
DcmDsd
这个容器包含两个参数:
- DcmDsdRequestManufacturerNotificationEnable:OEM可以通过此选项使能/失能诊断请求通知机制。
- DcmDsdRequestsupplierNotificationEnabled:供应商可以通过此选项使能/失能诊断请求通知机制。
DcmDsdServiceTable
服务不支持回复NRC,建议与标准一致:0x7F
DcmDsp
建立DCM子模块,并配置DcmDspDataDefaultEndianness为大端。
DcmDspSecurity
配置安全等级管理参数,主要涉及下面两个:
- DcmRbDspSecurityStoreseed:是否保存Seed,这里选择否,种子由应用层函数生成。
- DcmDspSecurityMaxAttemptCounterReadoutTime:单位为秒,从启动到诊断模块启动延时。
DcmDspSecurityRow
安全等级定义,这里只有安全等级1的定义,等级3是Boot使用。下面是它的主要参数说明。
- DcmDspSecurityAttemptCounterEnabled:是否存储安全访问尝试次数。
- DcmDspSecuritycompareKeyFnc:比较Key的函数名称,遵循生成的函数原型声明,集成开发商需要实现此函数具体实现。
- DcmDspSecurityDelayTime:失败安全访问延时时间,以秒为单位。
- DcmDspsecurityDelayTimeOnBoot:启动延时,以秒为单位。
- DcmDspsecurityGetAttemptcounterFnc:获取安全访问尝试次数的函数名称,遵循生成的函数原型声明,集成开发商需要实现此函数具体实现。
- DcmDspSecurityGetSeedFnc:获取Seed的函数名称,遵循生成的函数原型声明,集成开发商需要实现此函数具体实现。
- DcmDspSecurityKeysize:安全密钥的长度,以字节为单位。
- DcmDspSecurityLevel:安全等级。
- DcmDspSecurityNumAttDelay:激活延迟时间内的失败安全访问次数。
- DcmDspSecuritySeedsize:安全种子长度,以字节为单位。
- DcmDspsecuritysetAttemptcounterFnc:设置安全访问尝试次数的函数名称,遵循生成的函数原型声明,集成开发商需要实现此函数具体实现。
- DcmDspsecurityUsePort:定义安全访问使用何种Interface。
DcmDspSession
配置会话管理参数,默认参数即可。
DcmDspSessionRow
建立三个会话,其中编程会话可以跳转到BOOT,这样Tester在切换到编程会话之后,程序会跳转到Boot。
DcmDsdService
DCM支持的服务定义,一般需要支持以下服务:
- DiagnosticSessionControl:0x10服务,诊断会话控制服务。
- ECUReset:0x11服务,ECU重启服务。
- SecurityAccess:0x27服务,安全访问。
- CommunicationControl:0x28服务,通信控制。
- TesterPresent:0x3E服务,诊断仪在线。
- ControlDTCSetting:0x85服务,DTC控制服务。
- ReadDataByIdentifier:0x22服务,DID读取。
- WriteDataByIdentifier:0x2E服务,DID写入。
- ClearDTC:0x14服务,清除故障码DTC服务。
- ReadDTC:0x19服务,读取DTC服务。
- RoutineControl:0x31服务,例程控制服务。
- InputOutputControlByIdentifier:0x2F服务,输入输出控制服务。
我们以第一个0x10服务为例来介绍以下配置过程,首先如下图配置服务,我们来介绍以下重要的配置项:
- DcmDsdSidTabFnc:诊断服务处理函数,用户可以通过摁下“Ctrl+Enter”来查找特定DCM支持的服务处理函数名。
- DcmDsdSidTabServiceld:服务ID。
- DcmDsdSidTabSubfuncAvail:是否包含子服务。
- DcmRbDsdSidTabScheduler:服务处理函数调度函数,由DcmMainScheduler调度。
- DcmRbDsdSidTabSidInitFunction:服务初始化函数,用户可以通过摁下“Ctrl+Enter”来查找特定DCM支持的服务初始化函数名。
- DcmDsdSidTabSecurityLevelRef:服务需要的安全等级,空为不需要安全等级。
- DcmDsdSidTabSessionLevelRef:服务需要的会话状态,全选即为在任何会话模式下都可以访问这个服务。
这个服务有三个,如下图所示,可以看到切换到编程模式的子服务只能在扩展模式下访问。
DcmDspComControlAllChannel
配置代表所有通信的ComM网络通道。
DcmDspCommonAuthorization
此容器配置常见的服务鉴权要求。
DcmRbDspReadDTC
这个容器主要涉及到两个参数。
- DcmRbDspReadDTCMaxNumDTCRead:在一个服务中最大能读取的DTC数量。
- DcmRbDspReadDTCMaxNumRecordRead:在一个服务中最大能读物的Record。
DcmDspData
这个容器包含了DID涉及的数据定义以及用户自定的读写函数名称,关键参数如下。
- DcmDspDataReadFnc:请求读取DID数据的函数名称,集成商需要实现。
- DcmDspDataSize:DID数据大小,以Bit为单位。
- DcmDspDataType:DID数据类型。
- DcmDspDataUsePort:定义访问数据使用的Interface,下面的示例用的是同步。
- DcmDspDataWriteFnc:请求写入DID数据的函数名称,集成商需要实现。
DcmDspDidInfo
这个容器包含了DID的一些属性信息,包括会话和安全等级要求。首先通过DcmDspDidDynamicallyDefined参数配置DID可否动态配置,如下图。
然后,新建DcmDspDidRead,在DcmDspDidWriteSessionRef处引用默认和扩展会话,表示这个DID在这两个会话下才能访问。
然后再新建DcmDspDidWrite,在DcmDspDidWriteSecurityLevelRef处引用安全等级为1,在DcmDspDidWriteSessionRef引用扩展会话,这样针对F190这个DID(也就是VIN码)的写操作只有在安全等级为1且扩展模式下才能访问。
DcmDspDid
这个容器定义一个具体的DID,它会引用到我们刚才定义的DidInfo以及Data信息,我们首先在DcmDspDidldentifier处填写DID值,然后再在DcmDspDidInfoRef处引用刚才定义的DidInfo。
最后我们新建一个DcmDspDidSignal,它包含以下两个参数。
- DcmDspDidDataPos:在下边引用的DcmDspData中数据DID的起始位置。
- DcmDspDidDataRef:DID引用的DcmDspData。
DcmDspRoutine
这个容器包含了例程相关的配置。重要的配置如下:
- DcmDspRoutineldentifier:例程ID。
- DcmDspRoutineUsePort:例程会生成一个Interface,应用层可以基于这个Interface建立一个Service类型端口实现例程执行内容。
建立一个启动例程的子服务。
最后我们定义一个单字节的ECU回复信息。新建一个DcmDspStartRoutineOut,下面是该容器的具体配置。
DcmPageBuffercfg
禁用PageBuffer机制。
CanTp
CanTp(CAN Transport Layer)是在PDU Router与CAN Interface module中间的模块,如下图所示。CANTP模块的主要目的是分段和重新组装长度大于8字节或在CAN_FD情况下大于64字节的CANI-PDU(根据传输层定义,拼接CAN帧供应用层使用)。
PDU Router将AUTOSAR COM和DCM I-PDU部署到不同的通信协议上。通过网络系统类型(如CAN、LIN和FlexRay)的路由行为取决于I-PDU标识符。PDU Router还确定是否必须使用传输协议。最后,当没有速率转换时,该模块执行网关功能。
CAN Interface module(Canlf)提供同等的机制来访问CAN总线通道,而不论其位置(芯片内部或者外部)。它从CAN控制器的位置(芯片或者板载)中提取ECU硬件布局和CAN驱动程序的数目。由于CanTp只处理传输协议帧(即SF、FF、CF和FC PDU),根据N-PDU标识,CANIf必须将I-PDU转发给CanTp或PduR。下图中的红色箭头为DCM诊断协议的路径。
根据AUTOSAR的基本软件架构,CanTp可以提供:
- 在传输方向上的数据分割。
- 沿接收方向重新拼接数据。
- 数据流的控制。
- 检测会话中的错误。
- 发送与接收取消。
AUTOSAR决定将基本的软件模块规范建立在现有标准之上,因此本AUTOSAR CAN传输层规范以国际标准ISO-15765为基础,IS015765是汽车领域最常用的标准。
ISO-15765(包含四个部分)描述了两种适用的CAN传输层规范:ISO-15765-2用于OEM增强型诊断和ISO-15765-4标准用于OBD诊断。过CAN传输层配置,可以解决ISO-15765-2和SO-15765-4之间的兼容性问题。
虽然CAN传输协议主要用于车辆诊断系统,但它也被开发用于处理其他基于CAN的系统需要传输层协议的要求。
CanTpGeneral
此容器包含针对CanTP的一些通用配置。下面针对重要的参数进行解释。
- CanTpChangeParameterApi:如果设置为真,则可以使用CanTp_ChangeParameterRequest在运行中改变参数。
- CanTpDevErrorDetect:模块DET使能。
- CanTpPaddingByte:未使用Bytes的默认值。
- CanTpReadParameterApi::如果设置为真,则可以使用CanTp_ReadParameterApi读取运行中的参数配置。
CanTpChannel
在CanTpConfig容器下配置CanTpMainFunctionPeriod为0.01。
在CanTpChannel容器下配置CanTpChannelMode为CANTP_MODE_FULL_DUPLEX全双工。
CanTpRxNSdu
为每个CanTp接收的N-SDU配置参数,这里DCM涉及两个报文,一个物理请求ID报文,一个功能请求ID报文,我们先介绍物理请求ID报文。
其中主要涉及的配置项包括:
- CanTpNbr:下一个个FlowControl传输之前的时间。
- CanTpRxAddressingFormat:接收帧ID类型,下面实例为标准帧。
- CanTpRxPaddingActivation:定义接收的帧未使用字节是否填充。
- CanTpRxTaType:定义当前Rx N-SDU的通信类型。
- CanTpRxNSduRef:当前接收报文CanTp2PduR的引用。
我们还需要引用物理请求帧CanTp与CanIf之前来回的Pdu。
首先是物理请求帧对应的CanIf2CanTp的Pdu引用。
因为物理帧的请求一般需要回复,所以这里还需要引用诊断响应帧的CanTp2CanIf,如下图所示。
后边还需要配置功能请求帧的配置,如下如所示,与物理请求帧基本一致,不同的是CanTpRxNSduRef的引用为功能请求帧。
功能请求帧一般不需要回复,所以只需要引用功能帧的CanIf2CanTp即可。
CanTpTxNSdu
为每个CanTp发送的N-SDU配置参数,DCM这边仅涉及一个诊断响应帧,其中涉及到的主要配置参数如下:
- CanTpNas:发送任意CAN帧的时间。
- CanTpTc:启用/禁止传输取消功能。
- CanTpTxAddressingFormat:发送帧ID的类型,下面的示例为标准帧。
- CanTpTxPaddingActivation:定义发送的帧未使用字节是否填充。
- CanTpTxTaType:定义当前Tx N-SDU的通信类型。
- CanTpTxNSduRef:当前发送报文PduR2CanTp的引用。
我们还需要引用诊断响应帧CanTp与CanIf之前来回的Pdu。因为诊断响应帧一般回复的是物理请求帧,所以CanTpRxFcNPdu引用物理请求帧的CanIf2CanTp。
然后是诊断响应帧本身的CanTp2CanIf。
Components
使用CodeGen生成BSW代码以及ARXML成功之后,就可以在Components下看到生成的DCM服务组件。服务组件的东西都是生成的,不用更改,这里就不介绍了。
我们在测试建立的组件Test1中完成DCM相关服务的实现支持,首先建立三个端口如下图,并引用DTS_DcmEcuReset,它与端口使用的接口都是CodeGen生成的。
然后我们建立四个Functions:
- RE_JumpToBootloader:实现跳转到BootLoader功能,可以增加对MDGP_DcmEcuReset的Mode Points访问,RTE会给它提供当前DcmEcuReset模式获取接口。
- RE_Dcm_Reset_Hard:实现硬重启,访问EcuM提供的SelectShutdownTarget。
- RE_Dcm_Reset_Soft:实现软重启,访问EcuM提供的SelectShutdownTarget。
- RE_Swc_DcmDspRoutine_F001_Start:实现F001例程,可以连接必要的应用组件。
最后,建立对应的Events。
System
将DCM增加部件中。
然后增加DCM服务组件到ECU中。
最后完成连接组件间的连接。
RTE
将BSWSE DcmMainFunction添加到周期运行函数中,因为RE_JumpToBootloader,RE_Dcm_Reset Soft、RE_Dcm_Reset_Hard三个运行实体牵扯到模式的转换,所以需要将它们放到DcmMode切换的专用Task中,这个Task为RTE使用,用作本地的模式切换。
代码解析
动态配置代码
DCM模块生成的动态代码如下图所示。
我们下面针对一些常用的进行说明:
- Dcm_Cfg_DslDsd.h:它包含了Diagnostic Communication Manager (DCM)模块中Data Services (DSD)和Diagnostic Session Layer (DSLl)之间的数据结构和宏定义。该头文件定义了DSL和DSD之间交换的消息格式、DCM状态机的状态、DCM会话的类型、DCM数据的长度等信息。
- Dcm_Cfg_DspUds.h:该文件定义了UDS协议中各种服务的标识符、支持的诊断服务、支持的协议控制信息、支持的诊断服务的请求和响应的最大长度、支持的DTCS(Diagnostic Trouble Code)格式等。
- Dcm_Lcfg_DslDsd.c:它包含了DSD与DSL使用的服务列表、诊断协议支持等静态常量。
- Dcm_Lcfg_DslDsd.h:包含了DCM函数原型定义。
/* *********************************************************************************************************************** * * Product Info * Isolar version: ISOLAR-AB 4.0.2 * Product release version: RTA-BSW 3.1.0 * *********************************************************************************************************************** */ #ifndef _DCM_LCFG_DSLDSD_H #define _DCM_LCFG_DSLDSD_H #define DCM_START_SEC_CODE /*Adding this for memory mapping*/ #include "Dcm_Cfg_MemMap.h" extern FUNC(Std_ReturnType,DCM_CODE) Dcm_DcmDiagnosticSessionControl(VAR( Dcm_SrvOpStatusType,AUTOMATIC) OpStatus,P2VAR(Dcm_MsgContextType,AUTOMATIC,DCM_INTERN_DATA) pMsgContext,P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) dataNegRespCode_u8); extern FUNC(Std_ReturnType,DCM_CODE) Dcm_DcmEcuReset(VAR( Dcm_SrvOpStatusType,AUTOMATIC) OpStatus,P2VAR(Dcm_MsgContextType,AUTOMATIC,DCM_INTERN_DATA) pMsgContext,P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) dataNegRespCode_u8); extern FUNC(Std_ReturnType,DCM_CODE) Dcm_DcmSecurityAccess(VAR( Dcm_SrvOpStatusType,AUTOMATIC) OpStatus,P2VAR(Dcm_MsgContextType,AUTOMATIC,DCM_INTERN_DATA) pMsgContext,P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) dataNegRespCode_u8); extern FUNC(Std_ReturnType,DCM_CODE) Dcm_DcmReadDataByIdentifier(VAR( Dcm_SrvOpStatusType,AUTOMATIC) OpStatus,P2VAR(Dcm_MsgContextType,AUTOMATIC,DCM_INTERN_DATA) pMsgContext,P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) dataNegRespCode_u8); extern FUNC(Std_ReturnType,DCM_CODE) Dcm_DcmWriteDataByIdentifier(VAR( Dcm_SrvOpStatusType,AUTOMATIC) OpStatus,P2VAR(Dcm_MsgContextType,AUTOMATIC,DCM_INTERN_DATA) pMsgContext,P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) dataNegRespCode_u8); extern FUNC(Std_ReturnType,DCM_CODE) Dcm_DcmRoutineControl(VAR( Dcm_SrvOpStatusType,AUTOMATIC) OpStatus,P2VAR(Dcm_MsgContextType,AUTOMATIC,DCM_INTERN_DATA) pMsgContext,P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) dataNegRespCode_u8); extern FUNC(Std_ReturnType,DCM_CODE) Dcm_DcmCommunicationControl(VAR( Dcm_SrvOpStatusType,AUTOMATIC) OpStatus,P2VAR(Dcm_MsgContextType,AUTOMATIC,DCM_INTERN_DATA) pMsgContext,P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) dataNegRespCode_u8); extern FUNC(void,DCM_CODE) Dcm_Dsp_DscIni(void); extern FUNC(void,DCM_CODE) Dcm_Dsp_EcuReset_Ini(void); extern FUNC(void,DCM_CODE) Dcm_Dsp_SecaIni(void); extern FUNC(void,DCM_CODE) Dcm_Dsp_RdbiIni(void); extern FUNC(void,DCM_CODE) Dcm_Dcm_WDBIInit(void); extern FUNC(void,DCM_CODE) Dcm_Dsp_RC_Ini(void); extern FUNC(void,DCM_CODE) Dcm_Dsp_CCIni(void); extern FUNC(Std_ReturnType,DCM_APPL_CODE) DcmAppl_UserServiceModeRuleService(P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) Nrc_u8, VAR(uint8,AUTOMATIC) Sid_u8); extern FUNC(Std_ReturnType,DCM_APPL_CODE) DcmAppl_UserSubServiceModeRuleService(P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) Nrc_u8, VAR(uint8,AUTOMATIC) Sid_u8,VAR(uint8,AUTOMATIC) Subfunc_u8); extern FUNC(Std_ReturnType,DCM_APPL_CODE) DcmAppl_UserDIDModeRuleService(P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) Nrc_u8, VAR(uint16,AUTOMATIC) did_u16,VAR(Dcm_Direction_t,AUTOMATIC) dataDirection_en); extern FUNC(Std_ReturnType,DCM_APPL_CODE) DcmAppl_UserRIDModeRuleService(P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) Nrc_u8, VAR(uint16,AUTOMATIC) rid_u16, VAR(uint8,AUTOMATIC) subfunction_u8); extern FUNC(Std_ReturnType,DCM_APPL_CODE) DcmAppl_UserCommCtrlReEnableModeRuleService(void); /* Extern declarations For DcmAppl SessionMode Switch function */ extern FUNC(void,DCM_CODE) DcmAppl_Switch_DcmDiagnosticSessionControl(VAR(Dcm_SesCtrlType,AUTOMATIC) SessionMode); extern FUNC(void,DCM_CODE) DcmAppl_Switch_DcmExecuteDscReset(VAR(uint8,AUTOMATIC) SessionLevel_u8); /* Extern declarations For DcmAppl ResetMode Switch function */ extern FUNC(void,DCM_CODE) DcmAppl_Switch_DcmEcuReset(VAR(uint8,AUTOMATIC) ResetMode); extern FUNC(void,DCM_CODE) DcmAppl_Switch_DcmExecuteReset(void); extern FUNC(void,DCM_CODE) DcmAppl_Switch_DcmExecuteEcuReset(VAR(uint8,AUTOMATIC) ResetType_u8); extern FUNC(void,DCM_CODE) DcmAppl_Switch_DcmBootLoaderReset(void); extern FUNC(void,DCM_CODE) DcmAppl_Switch_DcmSysSupplierReset(void); extern FUNC(void,DCM_CODE) DcmAppl_Switch_DcmDriveToDriveReset(void); #define DCM_STOP_SEC_CODE /*Adding this for memory mapping*/ #include "Dcm_Cfg_MemMap.h" #endif /* _DCM_LCFG_DSLDSD_H */
- Dcm_Lcfg_DspUds.c:包含会话与密钥管理配置以及DID,Routines相关Dsp配置。
- Dcm_Lcfg_DspUds.h:DSP涉及的DID读写以及例程相关函数原型。
/* *********************************************************************************************************************** * * Product Info * Isolar version: ISOLAR-AB 4.0.2 * Product release version: RTA-BSW 3.1.0 * *********************************************************************************************************************** */ #ifndef DCM_LCFG_DSPUDS_H #define DCM_LCFG_DSPUDS_H /* *************************************************************************************************** * DCM Appl API Prototyes generated from configuration *************************************************************************************************** */ #define DCM_START_SEC_CODE /*Adding this for memory mapping*/ #include "Dcm_Cfg_MemMap.h" extern FUNC(Std_ReturnType,DCM_APPL_CODE) Dcm_DidServices_F186_ReadData(P2VAR(uint8,AUTOMATIC,DCM_INTERN_DATA) adrData_pu8); #define DCM_STOP_SEC_CODE /*Adding this for memory mapping*/ #include "Dcm_Cfg_MemMap.h" #define DCM_START_SEC_CODE /*Adding this for memory mapping*/ #include "Dcm_Cfg_MemMap.h" /***Extern declarations to obtain NRC value from the application in case of E_NOT_OK return from ReadData API ***/ extern FUNC(Std_ReturnType,DCM_APPL_CODE) DcmAppl_DcmReadDataNRC(VAR(uint16,AUTOMATIC)Did,VAR(uint32,AUTOMATIC)DidSignalPosn,P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) ErrorCode); /***Extern declarations for XXX_ReadData of type USE_DATA_SYNCH_FNC ***/ extern FUNC(Std_ReturnType,DCM_APPL_CODE) DcmDspDataReadFnc_F190 (P2VAR(uint8,AUTOMATIC,DCM_INTERN_DATA) Data); extern FUNC(Std_ReturnType,DCM_APPL_CODE) DcmDspDataWriteFnc_F190 (P2CONST(uint8,AUTOMATIC,DCM_INTERN_DATA) Data,P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) ErrorCode); /***Routine control Appl functions***/ /***Seca dcmDspSecurityGetSeedFnc functions with Useport USE_ASYNCH_FNC ***/ extern FUNC(Std_ReturnType, DCM_APPL_CODE) DCM_SEC_LEV_L1_GetSeed(VAR(Dcm_SecLevelType,AUTOMATIC) SecLevel_u8,VAR(uint8,AUTOMATIC) Seedlen_u8,VAR(uint8,AUTOMATIC) AccDataRecsize_u8,P2VAR(uint8,AUTOMATIC,DCM_INTERN_DATA) SecurityAccessDataRecord,P2VAR(uint8,AUTOMATIC,DCM_INTERN_DATA) Seed,VAR(Dcm_OpStatusType,AUTOMATIC) OpStatus,P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) ErrorCode); /***Seca dcmDspSecurityCompareKeyFnc functions with Useport USE_ASYNCH_FNC ***/ extern FUNC(Std_ReturnType, DCM_APPL_CODE) DCM_SEC_LEV_L1_CompareKey(VAR(uint8,AUTOMATIC) KeyLen,P2VAR(uint8,AUTOMATIC,DCM_INTERN_CONST) Key,VAR(Dcm_OpStatusType, AUTOMATIC) OpStatus,P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) ErrorCode); /***Seca dcmDspSecurityGetAttemptCounterFnc functions with Useport USE_ASYNCH_FNC ***/ extern FUNC(Std_ReturnType, DCM_APPL_CODE) Dcm_SEC_LEV1_GetSecurityAttemptCounter( VAR(Dcm_OpStatusType, AUTOMATIC) OpStatus,P2VAR(uint8,AUTOMATIC,DCM_INTERN_DATA) AttemptCounter); /***Seca dcmDspSecuritySetAttemptCounterFnc functions with Useport USE_ASYNCH_FNC ***/ extern FUNC(Std_ReturnType, DCM_APPL_CODE) Dcm_SEC_LEV1_SetSecurityAttemptCounter( VAR(Dcm_OpStatusType, AUTOMATIC) OpStatus,VAR(uint8,AUTOMATIC) AttemptCounter); #define DCM_STOP_SEC_CODE /*Adding this for memory mapping*/ #include "Dcm_Cfg_MemMap.h" #endif /* DCM_LCFG_DSPUDS_H */
集成代码
MemMap与SchM就不在这里赘述了。DCM提供了很多诊断通知函数的模板,它们会在DCM运行中在特定位置调用这些函数,诸如通知ECU重启类型,或者实现一些特殊接口,诸如实现内存读取。它们一般情况下都不会用到。它们涉及很多,下图截取了一部分
还有刚才提到的那四个函数RE_JumpToBootloade、RE_Dcm_Reset_Soft、RE_Dcm_Reset_Soft、RE_Swc_DcmDspRoutine_F001_Start实现,下面以JumpToBootload为例。
FUNC (void, Diag_SWC_CODE) RE_JumpToBootloader_func/* return value & FctID */
(
void
)
{
/* Local Data Declaration */
/*PROTECTED REGION ID(UserVariables :RE_JumpToBootloader_func) ENABLED START */
/* Start of user variable defintions - Do not remove this comment */
/* End of user variable defintions - Do not remove this comment */
/*PROTECTED REGION END */
Std_ReturnType retValue = RTE_E_OK;
/* -------------------------------------- Data Read ----------------------------------------- */
/* -------------------------------------- Server Call Point -------------------------------- */
/* -------------------------------------- CDATA --------------------------------------------- */
/* -------------------------------------- Data Write ---------------------------------------- */
/* -------------------------------------- Trigger Interface --------------------------------- */
/* -------------------------------------- Mode Management ----------------------------------- */
/* -------------------------------------- Port Handling ------------------------------------- */
/* -------------------------------------- Exclusive Area ------------------------------------ */
/* -------------------------------------- Multiple Instantiation ---------------------------- */
/*PROTECTED REGION ID(User Logic :RE_JumpToBootloader_func) ENABLED START */
/* Start of user code - Do not remove this comment */
*(uint32 *)PROG_REQUEST_ADDR = (uint32)PROG_REQUEST_NUMBER;
Mcu_PerformReset();
/* End of user code - Do not remove this comment */
/*PROTECTED REGION END */
}
可以看到跳转Boot的函数首先在内存的一个预设的位置配置为有编程请求,然后通过调用MCU提供的Mcu_PerformReset执行重启,因为Boot执行顺序在APP之前,所以先执行,然后再预设的位置获取了有编程请求的信息之后,即可以进入变成会话等待进一步的诊断协议。
最后,集成商还需要根据刚才的配置区实现具体的DID读/写函数。下面是一个F190的示例。集成商应该根据自己平台的特点来修改示例。
FUNC(Std_ReturnType,DCM_APPL_CODE) DcmDspDataReadFnc_F190 (P2VAR(uint8,AUTOMATIC,DCM_INTERN_DATA) Data)
{
uint8 ptrdata[LENGTH_OF_F190] = {0};
uint32 index = 0u;
for(index = 0u; index < LENGTH_OF_F190 ; index++)
{
Data[index] = VIN[index];
}
return DIAG_E_OK;
}
FUNC(Std_ReturnType,DCM_APPL_CODE) DcmDspDataWriteFnc_F190 (P2CONST(uint8,AUTOMATIC,DCM_INTERN_DATA) Data,P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_INTERN_DATA) ErrorCode)
{
uint8 u8CycleCnt = 0U;
uint8 u8WriteRt = 1U;
for (u8CycleCnt = 0U; u8CycleCnt<LENGTH_OF_F190; u8CycleCnt++)
{
VIN[u8CycleCnt] = Data[u8CycleCnt];
}
while(u8WriteRt)
{
u8WriteRt = Rte_Call_RP_F190_NvM_WriteBlock(VIN);
}
return u8WriteRt;
}
静态代码
主要介绍常见的静态代码涉及API说明,具体详细完整的介绍读者可以参考《AUTOSAR_SWS_CANTransportLayer.pdf》以及《RTA-BSWReferenceGuide.pdf》。
- Dcm_MainFunction:DCM模块主函数,需要循环调用处理DCM相关任务。
- Dcm_ReadMemory:这是一个CallOut函数,集成商根据DCM提供的函数原型实现存储的读取操作。
- Dcm_TxConfirmation:这是一个Callbcak函数,DCM发送完成时调用。
- Dcm_Init:这是一个提供给别的BSW组件的函数,完成DCM初始化。
- Dcm_GetSecurityLevel:这是一个提供给SW-Cs或者基础模块的函数,获取当前的安全等级。
十六宿舍 原创作品,转载必须标注原文链接。
©2023 Yang Li. All rights reserved.
欢迎关注 『十六宿舍』,大家喜欢的话,给个👍,更多关于嵌入式相关技术的内容持续更新中。