源码如下:
【免费】AUTOSAR-DEM源码资源-CSDN下载
AUTOSAR_DEM理论篇如下:
AUTOSAR CP故障诊断协议栈DEM(DTC)理论篇-CSDN博客
1. 引言
AUTOSAR CP 的诊断协议栈(DCM + DEM + FiM)功能完善、体系严谨,是汽车电子行业的标杆。但在实际项目中,尤其是电机控制器、BMS、VCU等资源敏感或非 CAN 诊断优先的场景,完整部署 AUTOSAR 诊断栈往往显得笨重:
-
需要复杂配置工具
-
大量代码生成
-
对 UDS、会话管理、安全访问等非核心功能依赖不强
因此,我们选择只聚焦 DEM(Diagnostic Event Manager) ,手写一个轻量级、可移植、易理解的故障管理内核,命名为 DSM(Diagnostic State Manager) / DIM(Diagnostic Information Manager)。
本文不涉及 AUTOSAR 工具配置,重点记录从理解故障管理本质、重构现有代码,到工程移植、验证扩展的全过程,核心突出模块结构设计与逻辑梳理。
2. AUTOSAR 诊断协议栈回顾(模块拆分核心逻辑)
AUTOSAR 将诊断功能拆分为 DCM、DEM、FiM 三个独立模块,核心逻辑是基于各模块的变更频率差异实现解耦,降低维护成本,三个模块的职责与特性如下:
三者协同逻辑清晰:DCM 守住通信入口,DEM 管理故障数据,FiM 管控应用行为。结合项目需求,我们仅聚焦 DEM 核心能力 ,DCM 与 FiM 预留扩展接口,后续按需轻量补充。

3. 代码整体架构(事件直驱型)
DSM 模块基于项目遗留代码改造,原始代码采用事件直驱架构,核心逻辑为"故障事件触发 → 状态更新 → 计数处理 → DTC 记录",具体结构如下:
采用 功能组 + 组内偏移 两级索引:
-
功能组:故障大类(如通信故障、硬件故障),共约 26 个
-
组内偏移:每个大类下的子故障,总计 109 个
-
状态存储:使用位域数组,每个功能组对应一个 16 位整数
调用方式:上层通过宏传入功能组和偏移,宏展开后调用底层处理函数。
内部流程:
-
授权检查
-
设置检测标志位
-
累加故障计数器(增量值可配置)
-
若计数器达到阈值,设置记录标志位
-
记录 DTC 并保存冻结帧
-
更新全局故障等级
恢复流程类似:递减计数器,归零时清除记录标志。
优点 :内存紧凑、执行快
缺点:可读性差、索引计算复杂、不易扩展
4.核心架构:从两级索引到线性 FaultID
原代码采用 功能组(Function) + 组内偏移(Type) 的两级索引方式,约 26 个功能组,共 109 个故障。状态存储使用位域数组,每个功能组对应一个 16 位整数。
这种设计内存紧凑,但存在明显缺点:
-
索引计算复杂,需要依赖偏移表
-
可读性差,不易扩展
-
上层调用需要知道功能组和偏移两个参数
重构思路 :将所有故障线性编号为 0 ~ N-1(FaultID),状态数组大小缩减为 (N+15)/16 个 16 位整数。通过 FaultID 直接计算组索引(FaultID >> 4)和位偏移(FaultID & 0x0F),无需偏移表。
配置数据(如计数器增量、减量、失效模式、DTC 编号等)原本就按全局索引排列,重构后直接使用 FaultID 访问,完全不变。
状态数组分为四类:
-
检测状态(当前是否检测到故障)
-
记录状态(是否已确认为历史故障)
-
授权状态(是否允许检测该故障)
-
记录忽略状态(特殊场景使用)
所有状态操作通过宏封装,上层无感知。
5.、主要技术难点与解决方案
难点1:两级索引向线性索引的重构
-
问题:原代码中大量宏和函数依赖 Function+Type,修改范围大,易出错。
-
解决 :先定义 FaultID 枚举,然后统一修改所有状态访问宏,将
Function, Type替换为faultId,并在宏内部计算组索引和位偏移。配置数组索引直接使用 faultId。函数接口也相应简化。
难点2:NVM 存储依赖
-
问题:原代码调用 NVM 写入接口,目标工程中 NVM 驱动尚未完成。
-
解决 :提供空实现函数
NvM_SetRamBlockStatus,仅作占位,不执行实际写入。同时保留 NVM 数据结构,后续可无缝对接真实驱动。
难点3:中断保护缺失
-
问题:原代码在修改状态数组时使用了中断挂起/恢复宏,目标工程未定义。
-
解决:将相关宏定义为空(若确认不会发生并发访问),或适配 RTOS 临界区接口。
难点4:魔法数字泛滥
-
问题 :代码中直接使用
255、0xFFFF、0x01等数字,可读性差。 -
解决 :全部替换为有意义的宏,如
DIM_u8FAULT_CNT_MAX、DIM_u16TIMESTAMP_IGN_INVALID、DIM_u8DTC_SS_REQUIRED等。
6、后续扩展
DSM 模块预留了 DCM 和 FiM 的扩展接口,后续若需要支持 UDS 诊断或功能抑制,可快速补充,无需重构核心逻辑:
6.1 轻量接入 DCM
当前 DSM 已具备 DTC 存储、状态管理能力,DCM 只需做"薄层映射",将 UDS 服务接口映射到 DSM 现有接口,无需实现完整 UDS 协议栈,核心映射关系如下:
| UDS 服务 ID | 服务名称 | 映射到 DSM 的接口 |
|---|---|---|
| 0x19 | ReadDTCInformation | 读取 DSM 中的 DTC 列表、状态字、冻结帧数据 |
| 0x14 | ClearDiagnosticInformation | 调用 DIM_vidClearFault() 或单个 DTC 清除接口 |
| 0x22 | ReadDataByIdentifier | 读取实时故障状态、计数器值、全局故障等级 |
6.2 轻量接入 FiM
FiM 无需实现复杂的抑制策略,只需建立"functionId → faultId"的映射表,提供统一的功能权限查询接口,应用层通过接口判断功能是否可执行,避免散落大量 if 判断
六、项目结果
最终我们成功将 DSM 模块移植到 工程中,编译通过,无链接错误。通过模拟故障注入(直接调用检测接口)可以验证:
-
故障检测状态位正确置位
-
计数器按配置增量累加,达到阈值后记录位置位
-
DTC 被存入 NVM 数据结构(内存中),冻结帧数据被捕获
-
全局故障等级随失效模式计数器动态变化
从 DEM 原理角度看,我们实现了:
-
事件去抖:通过计数器和可配置增量/减量实现(类似 DEM 的 debouncing)
-
DTC 状态管理:维护了 TestFailed、Pending、Confirmed 等状态位
-
快照存储:支持冻结帧(FF1)的锁定、复制和 NVM 管理
-
老化机制:通过老化周期计数器支持 DTC 自动清除(框架已预留)
未实现的部分(UDS 接口、复杂老化策略、多快照)可根据后续需求轻量补充,不影响当前使用。
这个轻量化 DEM 内核已满足项目对故障记录、等级输出和功能抑制的需求,且代码清晰、可移植性强,为后续接入 DCM 或 FiM 留出了清晰的扩展点。