第四章 Arctic Core源码解析 —— 生产级DCM全拆解
4.1 DCM全景——AUTOSAR诊断栈的透明大厦
你读完标准后,最大的疑问是什么
ISO 14229-1:2013告诉你“0x10是什么、0x27怎么交互、0x36的blockSequenceCounter怎么递增“——但它从来没有告诉你:这些东西在真实ECU代码里长什么样。
这一章我们拆开Arctic Core——一个开源的AUTOSAR Classic Platform实现——的诊断栈。Arctic Core的DCM(Diagnostic Communication Manager)源码在diagnostic/Dcm/目录下,五个核心文件,总共一万多行C代码。这一节先让你看清楚这栋“透明大厦“的结构——每一层、每一间房、每一条走廊的命名和职责。
AUTOSAR诊断栈的四模块架构
┌─────────────────────────────────────────────────────────┐
│ APPLICATION LAYER │
│ (SW-Cs, 通过RTE通信) │
├─────────────────────────────────────────────────────────┤
│ 诊断服务层 │
│ ┌──────────┐ ┌────────┐ ┌────┐ ┌──────┐ │
│ │ DCM │ │ DEM │ │ Dlt│ │ FiM │ │
│ │Diagnostic│ │Diagnost│ │ │ │Func │ │
│ │Comm │ │Event │ │Log │ │Inhib │ │
│ │Manager │ │Manager │ │&Trc│ │Mgmt │ │
│ └────┬─────┘ └───┬────┘ └──┬─┘ └──┬───┘ │
│ │ │ │ │ │
│ │ DTC状态 │ 寄存器/端口/日志接口 │
│ └─────────────┘ │
├─────────────────────────────────────────────────────────┤
│ 通信层 (PduR) │
│ CanTp / DoIP / FrTp │
├─────────────────────────────────────────────────────────┤
│ 硬件抽象层 + 芯片驱动 │
└─────────────────────────────────────────────────────────┘
这四大模块各自负责诊断管线的不同阶段:
| 模块 | 完整名称 | 一句话职责 |
|---|---|---|
| DCM | Diagnostic Communication Manager | 收到UDS请求→解析→分发→执行→回复。诊断通信的核心服务器 |
| DEM | Diagnostic Event Manager | 存储DTC、管理DTC状态位、Debounce、快照/扩展数据 |
| DLT | Diagnostic Log and Trace | 诊断日志记录——将诊断交互写入持久存储或串口输出 |
| FiM | Function Inhibition Manager | 函数级抑制——根据DTC严重度临时停用ECU的某些功能块 |
这一章专注DCM——因为它是UDS应用层的全部实现。DEM会在4.8节简要覆盖其与DCM的交互接口。
DCM内部的三层——ISO 14229-1的直接映射
DCM内部进一步分解为三个子模块——对应ISO标准中“诊断请求受理→路由→服务处理“的三个阶段:
CAN/DoIP → PduR → DCM
│
┌──────┴──────────┐
│ SID提取/子功能解析
│
┌───────┤ DSL │←──────┤ 会话层
│ │ Diagnostic │ │
│ │ Session Layer │ │
│ └────────┬────────┘ │
│ │ │
│ ┌────────┴────────┐ │
│ │ DSD │←──────┤ 调度层
│ │ Diagnostic │ │
│ │ Service │ │
│ │ Dispatcher │ │
│ └────────┬────────┘ │
│ │ │
│ ┌────────┴────────┐ │
│ │ DSP │←──────┤ 执行层
│ │ Diagnostic │ │
│ │ Service │ │
│ │ Processor │ │
│ └─────────────────┘ │
└─────────────────────────────────┘
| 层 | 缩写 | 文件 | 代码量 | 核心职责 | 医院类比 |
|---|---|---|---|---|---|
| 会话层 | DSL | Dcm_Dsl.c | 1828行 | 缓冲区管理、Rx/Tx状态机、S3超时、协议抢占 | 门诊前台——挂号、分配候诊室、到期踢人 |
| 调度层 | DSD | Dcm_Dsd.c | 915行 | SID表查找、会话/安全鉴权、子功能分发、正/负响应创建 | 分诊护士——根据病人的“主诉“判断挂哪个科的号,检查有没有权限 |
| 执行层 | DSP | Dcm_Dsp.c | 6492行 | 全部22个UDS服务的业务逻辑实现 | 每个科室的医生——真正执行诊断操作 |
Dcm.c(358行)是总控——Dcm_Init和Dcm_MainFunction调用这三个子模块的入口,保证执行顺序是DspPreDsdMain → DsdMain → DspMain → DspTimerMain → DslMain。
DSL(会话层)——不仅仅是收发缓冲区
这是DCM的最外层,直接面对传输层(PduR)。DSL的核心状态是一个缓冲区的六态机:
NOT_IN_USE → IN_USE → PROVIDED_TO_PDUR → DSD_PENDING_RESPONSE_SIGNALED
→ DCM_TRANSMIT_SIGNALED
→ PROVIDED_TO_PDUR (发送中)
→ PENDING_BUFFER_RELEASE → NOT_IN_USE
这六种状态分别对应UDS请求从“传输层开始接收“到“DCM处理完成、回传响应、释放缓冲“的全部生命周期。DSL有两个Rx缓冲区和两个Tx缓冲区——一个“外部“(大块数据,给传输层的PDU),一个“内部“(本地小buffer,给响应NRC和responsePending等不需要大缓冲的场景)。
DSL还负责:协议启动/停止(StartProtocol/StopProtocol回调链)、会话切换时调用DspResetDiagnosticActivityOnSessionChange、功能寻址和物理寻址的统一管理。
DSD(调度层)——SID表查找器
DSD的核心数据结构是一个SID查找表——DsdServiceTable[]——每一行绑定一个SID、可选的子功能表、会话和安全的鉴权引用表、以及处理函数的函数指针。Arctic Core支持三种协议同时运行——CAN、FlexRay、DoIP——每种协议有自己的DsdServiceTable实例。
DSD的主函数DsdHandleRequest()流程:
1. 从 Rx buffer 读出 SID (pduRxData->SduDataPtr[0])
2. lookupSid(sid) —— 在 SID 表中线性搜索
3. 找到后调用 DspCheckSessionLevel —— 当前会话是否允许这个SID
4. 再调用 DspCheckSecurityLevel —— 当前安全等级是否允许
5. 如果有子功能码——调用 DsdLookupSubService() 查找子功能配置
6. 最终调用 selectServiceFunction → runInternalService(SID)
—— 这是一个巨大的 switch(SID) 分发到 DspUds* 函数
DSP(执行层)——所有UDS服务在这里变成C代码
6492行的Dcm_Dsp.c是DCM最大的文件——它实现了第2章每一节讲到的全部22个UDS服务的业务逻辑。你在Dsp.c里看到的每一个DspUdsXxx()函数,都直接对应你在第2章读过的那一个SID。
核心结构:
// DspUdsDiagnosticSessionControl(0x10) —— 会话切换
// DspUdsEcuReset(0x11) —— ECU复位
// DspUdsSecurityAccess(0x27) —— Seed/Key
// DspUdsReadDataByIdentifier(0x22) —— 按DID读
// DspUdsWriteDataByIdentifier(0x2E) —— 按DID写
// DspUdsReadDtcInformation(0x19) —— 读DTC
// DspUdsRoutineControl(0x31) —— 例行控制
// ...
// 总计 22+ 个服务处理函数
本篇小结
- Arctic Core的DCM遵循AUTOSAR架构——DSL管理通信会话和缓冲区,DSD进行SID路由和鉴权,DSP执行具体的UDS服务逻辑。
- Dcm.c作为总控,Init和MainFunction的调用顺序决定三层子模块的执行周期。
- DSL的六态缓冲区管理是实现“CAN帧→DCM内部消息→响应回传“全流程的核心。
- DSD的SID查找表+会话/安全鉴权+子功能分发形成UDS请求的路由决策树。
- DSP是UDS协议规范到C代码的1:1映射——每一节第二章的内容在DSP中有一个函数。
【下集预告】:总控的MainFunction每个周期都干了些什么?Init初始化了什么?PduR把数据喂给DCM后——Dcm_StartOfReception→Dcm_CopyRxData→Dcm_TpRxIndication这三步是怎么协作的?我们拆开Dcm.c的每一行。