AUTOSAR入门-Dcm模块
原创 thatway 那路谈OS与SoC嵌入式软件 2022-04-13 18:03
AUTOSAR入门-Dcm模块
先复习下**AS代码**
之前做过的试验:AUTOSAR入门-基于以太网诊断
。我们通过网络发送DoIP报文
,实现了对汽车EcuReset的功能,报文通过的模块依次为:
网卡驱动-》网络接口-》LWIP网络协议栈-》SoAd模块-》DoIP模块-》PduR模块-》Dcm模块
。
我们**倒着**
从功能角度入手,结合AUTOSAR规范从Dcm模块
开始讲解下AS里面里面的处理过程,Dcm模块是我们第一个讲的AUTOSAR的模块,其他模块的所有套路在AUTOSAR框架里面都是相通的,这里我希望能做到
抛砖引玉的效果。
0. 准备工作
研究AUTOSAR规范,首先要知道官网:
https://www.autosar.org
官网资料是其他资料的源头,最权威的内容, 通常工作中会像字典一样反复查阅。
首先打开:
https://www.autosar.org/nc/document-search/
按下图下载规范:
AUTOSAR_SWS_DiagnosticCommunicationManager.pdf
或者直接输入如下网址查看:
首先说下这个文档该怎么看,从这文件的名字上有**SWS**
,这个意思是软件规范,也是我们作为开发人员主要看的内容。其他的前缀解释如下:
EXP: 即Explaination"解释",详细介绍论题
MMOD: 即MetaModel"元模型",介绍 AUTOSAR元模型
MOD: 即Model"建模",介绍建模的原理
RS: 即RequirementSpecification"需求规范", 详细介绍需求
SRS: 即SoftewareRequirement Specification"软件需求规范", 描述所有软件模块的规范
SWS: 即SoftewareSpecification"软件规范", 介绍软件模块设计和实现的规范
TPS: 即TemplateSpecification"模板规范", 详细介绍元模型
TR: 即TechnicalSpecification"技术规范",详细介绍技术规范
然后SWS后面的
DiagnosticCommunicationManager就是功能模块的命名,首字母可以看出来就是DCM
。
上图中红色
标识出来的就是我们需要重点关注的,本文也是按照这个顺序进行展开,下面带着大家按这个文档
来看一遍来,了解Dcm。
1. 简介和功能介绍
打开这个pdf文档,第一部分如下:
重点看下这个图,通过诊断工具
连接到汽车上的板卡
上,可以跟板卡里面的Dcm模块
通信。
那么通信干什么呢?
接着往下看:
这段英语翻译过来为:
Dcm
模块确保诊断数据流并管理诊断状态
,特别是诊断会话和安全状态。此外,
Dcm
模块根据诊断状态检查是否支持
诊断服务请求
,以及服务是否可以在当前会话中执行。
那么提供什么服务
呢?答案就是UDS和OBD服务,这是两种应用协议,这里我们以UDS为例说明,UDS
(
Unified Diagnostic Services)里面有什么服务呢?
查看ISO14229 手册(公众号回复ISO
获取):
从第9章开始,有这么多服务,用到哪个就去查这个手册。
下面这个图更加直观一点:
诊断可以提供什么服务是不是一目了然,比如车坏了,要知道怎么坏的,可以去**读数据**
。可以设置参数写数据
,可以控制设备
比如重启,总之跟车交互的功能基本都在里面。
下面继续以之前做的以太网诊断为例进行说明,我们发的DoIP报文如下:
报文里面的11 01
就是包装的UDS报文
的内容,通过查询上面的SID
,我们知道11是复位
,继续查01是硬件复位
的意思:
上面说了挺多的介绍,业务方面介绍差不多了,大家应该知道Dcm是干什么的了,就是实现**UDS里面规定的服务**
。但是只讲概念是没有灵魂的,对于程序员来说:
Talk is cheap,show me the code!
打开AS**代码**
,先找到Dcm代码的位置:
Dcm_Dsd.c中selectServiceFunction()函数里面就是对于UDS报文id
的处理,
例如我们上面的0x11
如下:
然后01按照ISO14229
标准是硬重启,查看
DspUdsEcuReset()
函数:
处理完毕,也是按照**ISO14229**
的标准对外部诊断程序进行报文回应。
其他的服务执行逻辑根据switch自己查看代码。可以自己加log
打印,做实验看看代码是不是跑到这里了,应该是挺有意思
的事情。跟打游戏一样,体验下代码被你控制的感觉。
在1简介和功能介绍中,有一个Dcm在AUTOSAR位置的图:
可以参考:汽车电子构架演进(二)AUTOSAR的组成和演进
,了解Dcm的位置。
2. 缩略词:
看看拓展下知识面就可以,这里不说明。
3. 相关文档
: 可以了解下
4 假定和约束
: 这里不研究了。
5. 依赖模块
依赖模块这个列举出了,**跟Dcm模块交互**
的其他模块,可以了解到Dcm在ATUOSAR中的位置:
Dcm**和Dem的交互 :**
DEM模块提供了检索与故障内存相关的所有信息的功能,以便Dcm模块能够通过从故障内存中读取数据重新响应测试人员的请求,通俗的讲就是Dcm能够读取Dem记录的DTC信息。
Dcm和PduR的交互
:
PduR模块接收和发送诊断数据。PduR为Dcm模块提供一个与具体通信协议无关的接口。
Dcm和ComM模块的交互
:
Dcm模块可以指示状态“活动”和“非活动”用于诊断通信。Dcm模块提供了处理通信需求“完全/静默/无通信”的功能。此外,Dcm模块提供了在ComM模块要求时启用和禁用诊断通信的功能。
SWC**通过和RTE接口和Dcm交互:**
Dcm模块在完成诊断功能的时候需要通过RTE接口来读写/函数调用其他SWC的数据/服务。
BswM和Dcm模块的交互:
如果Dcm的初始化是从引导加载程序跳转的结果,则Dcm通知BswM应用程序已更新。Dcm也向BswM指示通信模式的改变。
上面的这些交互都是以**函数**
为基础的,具体到代码里面,还是以:AUTOSAR入门-基于以太网诊断
为例子说明。
当报文到达**PduR模块**
的时候,PduR模块需要调用Dcm模块
的代码,把报文传递给Dcm模块:PduR模块-》Dcm模块
。
在AS代码上需要处理PduR模块调用过来的两个函数,在Dcm.c中:
Dcm_ProvideRxBuffer
()//开始传输报文
Dcm_RxIndication
()//传输报文完毕
6. 需求跟踪暂时不关注
7. 功能规格
功能规格规定了Dcm的软件组成
,
这里先打个比方,比如到医院看病,首先有接待的部门,导医台
。然后知道去哪个科室看不了就
挂号
。最后到你了就去科室找医生看病
。Dcm主要由三部分组成:Dsl(导医台)、Dsd(挂号系统)、Dsp(科室看病)
,如下图所示:
查看官网文档解释如下:
翻译如下:
为了定义Dcm模块的功能,Dcm SWS将Dcm模块建模为以下子模块:
1)Diagnostic Session Layer
诊断会话层(DSL
)子模块:
DSL子模块负责保证与诊断请求和响应相关的数据流,监督和保证诊断协议定时,管理诊断状态(特别是诊断会话和安全)。
2)Diagnostic Service Dispatcher
诊断服务调度程序(DSD
) 子模块:
DSD子模块处理诊断数据流。子模块:
-通过网络接收新的诊断请求并将其转发给数据处理器。
-当数据处理器(如DSP子模块)触发时,通过网络传输诊断响应。
3)Diagnostic Service Processing
诊断服务处理 (DSP
)子模块:
DSP子模块处理实际的诊断服务请求(分别为子服务请求)。
下面还是以PduR发来的报文为例,进行说明
1)Dsl(导医台)负责接待
例如接收到PduR模块过来的消息后,如何处理,代码:
Dcm_ProvideRxBuffer函数
Dcm_ProvideRxBuffer
DslProvideRxBufferToPdur(dcmRxPduId, tpSduLength, (constPduInfoType**)pduI nfoPtr);
if (findRxPduIdParentConfigurationLeafs(dcmRxPduId,&protocolRx, &mainConnection, &conn ection, &protocolRow, &runtime)) {
if (externalRxBuffer->pduInfo.SduLength >=tpSduLength) { /** @req DCM443 */
if ((runtime->externalRxBufferStatus == NOT_IN_USE)&& (externalRxBuffer->externalBufferRuntimeData->status ==BUFFER_AVAILABLE)) {
externalRxBuffer->externalBufferRuntimeData->status = BUFFER_BUSY;
runtime->diagnosticRequestFromTester.SduDataPtr =externalRxBuffer->pduInfo.SduDataPtr;
runtime->diagnosticRequestFromTester.SduLength = tpSduLength;
*pduInfoPtr = &(runtime->diagnosticRequestFromTester);
runtime->externalRxBufferStatus = PROVIDED_TO_PDUR;
ret= BUFREQ_OK;
}
根据dcmRxPduId在Dcm的配置文件(scons studio生成,10中会说明
)中找到对应的配置,
如果
externalRxBuffer没被使用,有空间,那
么runtime就指向这个externalRxBuffer
最后返回OK。
整个处理过程在DSL,会话层面就处理完毕了。
Dcm_RxIndication函数
Dcm_RxIndication
DslRxIndicationFromPduR(dcmRxPduId, result);
runtime->externalRxBufferStatus = PROVIDED_TO_DSD; /**@req DCM241 */
if (runtime->externalTxBufferStatus == NOT_IN_USE) {
ASLOG( DCM, ("ExternalTx buffer available, we can pass it to DSD.\n"));
}
DsdDslDataIndication( // qqq: We are inside a critical section.
&(runtime->diagnosticRequestFromTester),
rotocolRow->DslProtocolSIDTable, /** @req DCM035 */
protocolRx->DslProtocolAddrType,
mainConnection->DslProtocolTx->DcmDslProtocolTxPduId,
&(runtime->diagnosticResponseFromDsd),
dcmRxPduId);
}
2)Dsd(挂号系统)负责排队分配医生
下面进入Dsd模块进行分发处理
DsdDslDataIndication
传入参数操作
dsdDslDataIndication = TRUE; //挂号成功,等待排队
把全局变量
dsdDslDataIndication 置位了,在Dcm模块的轮询函数,
Dcm_MainFunction(
void
)中
Dcm_MainFunction(void)
if (dsdDslDataIndication) {
dsdDslDataIndication = FALSE;
DsdHandleRequest(); //排队到了
}
进行任务分发,
DsdHandleRequest
currentSid = msgData.pduRxData->SduDataPtr[0];
if (lookupSid(currentSid, &sidConfPtr)) {
result =askApplicationForServicePermission(msgData.pduRxData->SduDataPtr,msgData.pduRxData->SduLength);
if (result == E_OK) {
selectServiceFunction(currentSid);//看病
}
SduDataPtr
就是UDS报文
11 01:02 fd 80 01 00 00 00 06 0e 80 00 22
1101
currentSid
就是报文中的11
selectServiceFunction(uint8 sid)
switch (sid){
case SID_ECU_RESET:
DspUdsEcuReset(msgData.pduRxData, msgData.txPduId, msgData.pduTxData);//给出治疗方案
}
到这里DSD完成了分发,接下来由DSP模块进行处理
3)Dsd(科室医生)负责看病干活
DspUdsEcuReset
reqResetType = pduRxData->SduDataPtr[1];
switch (reqResetType)
{
caseDCM_HARD_RESET:
dspUdsEcuResetData.resetType = reqResetType;
switch( DcmE_EcuReset(dspUdsEcuResetData.resetType) )
{
case E_OK:
pduTxData->SduDataPtr[1] = reqResetType;
pduTxData->SduLength = 2;
DsdDspProcessingDone(DCM_E_POSITIVE_RESPONSE);
break;
}
reqResetType
就是
11 01中的01,对应DCM_HARD_RESET
DcmE_EcuReset为功能实现函数,实现Ecu的重置,如果执行成功,则填充pduTxData信息,
有
DsdDspProcessingDone
函数,按照收报顺序的逆序再发给客户端。上面按照收诊断报文的逻辑对Dcm模块的框架
进行了说明。
8. API说明
对代码的实现进行了规范,主要分为两部分:类型定义
,函数定义
。
类型定义,下面看一个例子:
这对代码的规范,简直到了限定死
了的地步,命名,取值范围,在那个文件中定义都规定好了。可以自己在AS代码里面Dcm.h
里面看看有这个定义没。
函数定义,看一个例子:
返回Dcm模块的版本号。对函数的写法,参数的写法,返回值,在那个文件中声明都规定的
明明白白
。
查看代码,在Dcm.c里面,实现的函数比较少(AS代码中的arccore代码比较旧实现的比较少,最新的
基本都实现了,见
https://github.com/openAUTOSAR/classic-platform
,可以进行移植到AS平台),我们可以对照着研究下。
下面说下AUTOSAR模块代码运行的套路:
1)首先就是初始化
:Dcm_Init(void)
2)然后就是轮询
执行一个函数:Dcm_MainFunction(void)
3)如果有其他模块进行交互,先接待,挂到队列
上,2中轮询到了进行处理。
例如医院看病挂号Dsl成功后,Dsd里面就是轮询一个一个的处理排队的病人,就靠的这个Dcm_MainFunction。
9. 时序图
规定了各个模块交互时候,函数按时间的调用情况,这里以收取PduR模块发来的包的情况说明:
各个模块间报文传递都需要调用三个函数
AAA_BBBTpStartOfReception
:BBB发给AAA,准备接收报文
AAA_BBBTpCopyRxData
:BBB发给AAA,拷贝报文
AAA_BBBTpRxIndication
:BBB发给AAA,接收成功
确认
10. 配置相关
规定了配置工具也就是工具链如何实现,**AS平台**
有自己的工具链
。下面介绍下:首先看下代码里面配置相关的部分,在初始化的时候,需要用到配置DCM_Config
DCM_Config在build/posix/x86/ascore/config/Dcm_LCfg.c
中定义,
这个文件里面有一个大的全局结构体变量,结构体的子项还是结构体,一时无法看懂,不急,这个变量可以通过工具配置和生成,参考:
AS平台输入命令
scons studio启动
工具链,如下:
配置完毕,点击File-》Generate就可以生成c代码了。
AUTOSAR的方法论就是,工具链生成配置代码
+固定的BSW代码
一块参与编译,最后在板子上运行。
后记:
再强调一遍,做下之前的实验:[AUTOSAR入门-基于以太网诊断](http://mp.weixin.qq.com/s?__biz=MzUzMDMwNTg2Nw==&mid=2247483815&idx=1&sn=8603d2994641cbbb02d48ac0313d074b&chksm=fa528783cd250e9524080071c93ed2d7db49a074824f264587bd317f3fda28e746657c7161de&scene=21#wechat_redirect)
,然后自己动手打log调试
,结合代码来看AUTOSAR的各个模块。另外多看几遍AUTOSAR官网文档
,AUTOSAR的所有模块的文档都是按照这个格式
写的,所以看完一个其他的模块就容易多了,后续就不吃力了。
满满的**干货**
,看到这里,想学AUTOSAR又不知道怎么学,或者没动力的朋友,可以抽点时间操作下了,
师傅领进门,修行靠个人
。
Talk is cheap,show methe code!
后续会继续更新,纯
干货分享,无广告,不打赏,欢迎
转载,欢迎
评论交流!
往期
见话题标签:
AUTOSAR入门