网易首页 > 网易号 > 正文 申请入驻

UDS诊断服务处理详解:DCM模块的设计与实现(以0x22服务为例)

0
分享至


1. 概述

在AUTOSAR架构中,DCM(Diagnostic Communication Manager) 是诊断通信的核心模块,负责解析UDS协议、执行诊断服务并管理ECU的诊断状态。它就像ECU的“诊断大脑”,协调从底层接收到数据、执行服务、生成响应并发送的全流程。

本文以 0x22 ReadDataByIdentifier(按标识符读取数据) 服务为例,深入讲解DCM内部的处理机制,并提供可运行的C++示例代码。

2. UDS诊断栈中的DCM位置

诊断报文通过物理层(CAN/LIN/ETH)→ 网络层(CanTp)逐级向上递交。CanTp 负责将长报文重组为完整的UDS请求数据。当CanTp完成重组后,会调用DCM的入口函数(例如 Dcm_MainFunction 或 Dcm_ProcessRequest),将完整请求数据传递给DCM。

DCM承担以下职责:

  • 解析服务ID、子功能、寻址方式

  • 会话与安全管理

  • 请求格式与参数有效性检查

  • 调用具体服务处理函数

  • 构造响应(正响应或否定响应)并向下传递

3. 服务解析与检查流程(以0x22为例)

假设诊断仪发送了一条物理寻址的 22 11 22 请求,其中:

  • 服务ID = 0x22 (ReadDataByIdentifier)

  • DID(Data Identifier) = 0x1122

DCM会按顺序执行以下检查:

3.1 提取服务ID

从请求数据 [22, 11, 22] 中取出首字节 0x22,识别为 ReadDataByIdentifier 服务。

3.2 寻址方式判定

DCM从底层接收的PDU信息中获取CAN ID。如果CAN ID属于诊断物理寻址范围,则判定为物理寻址,要求ECU必须单独响应;如果是功能寻址,则需要根据UDS协议中“抑制正响应位”(在子功能中)决定是否响应(避免总线冲突)。为简化,本例假定为物理寻址,总是需要响应。

3.3 会话与安全检查

DCM内部维护当前诊断会话类型(默认会话0x01、编程会话0x02等)以及安全等级(Secured 或 Unlocked)。对于 0x22 服务:

  • 通常允许在默认会话下读取非敏感DID

  • 但某些安全关键DID(如VIN、序列号、加密密钥)要求ECU处于 解锁状态 或 特定会话

如果当前状态不满足要求,DCM立即构造否定响应,例如:

  • 0x7F 22 0x7E —— 子功能不支持或当前会话下不允许

  • 0x7F 22 0x33 —— 安全访问未通过

3.4 请求格式检查

0x22 服务的标准请求格式为 [服务ID, DID高字节, DID低字节],总长度应为3字节。若请求长度不足3字节,则返回否定响应:

  • 0x7F 22 0x13 —— 报文长度错误

3.5 DID有效性检查

DCM查询本地配置的DID列表(例如通过配置表或回调函数表)。如果 0x1122 未在ECU中定义,则返回否定响应:

  • 0x7F 22 0x31 —— 请求超出范围

若以上检查全部通过,DCM转入数据获取阶段。

4. DCM内部层次化调用结构

AUTOSAR DCM模块采用分层设计,将服务分发、参数校验、数据获取解耦。典型的调用层次如下:

Dcm_ProcessRequest (主入口)
├─ Dcm_MainStateMachine (状态机:空闲 -> 请求处理)
├─ Dcm_ServiceTableLookup (根据服务ID查找处理函数)
├─ Dcm_Service_ReadDataByIdentifier (服务级处理)
│ ├─ 执行服务通用检查(子功能支持等)
│ ├─ 提取DID
│ ├─ 调用 DID分发函数 Dcm_DID_ReadHandler
│ └─ 若失败则生成否定响应
└─ Dcm_DID_ReadHandler_0x1122 (DID级处理)
├─ 调用RTE端口读取应用数据(如传感器值)
├─ 或调用NvM读取存储块(如VIN)
└─ 组装正响应数据 [0x62, DID高, DID低, 数据...]

这种层次化设计的优点:

  • 高扩展性 :新增DID只需添加一个处理回调,无需修改核心解析逻辑。

  • 职责分离 :服务级处理负责通用逻辑,DID级处理负责具体数据访问。

  • 可配置性 :通过配置表即可控制DID的有效性、安全要求等。

5. C++代码示例(模拟DCM处理0x22服务)

以下代码模拟了一个简化但完整的DCM模块,实现了物理寻址下的 0x22 服务处理。代码包含了:请求检查、否定响应生成、服务分发、DID回调、数据获取。

#include  
          
#include
#include
#include
#include

// 模拟诊断请求和响应的数据结构
struct DiagRequest {
std::vector data; // 收到的UDS请求数据(不含CAN ID)
bool isFunctionalAddress; // true=功能寻址, false=物理寻址
};

struct DiagResponse {
std::vector data;
bool isPositive = false; // true=正响应, false=否定响应
};

// ECU当前诊断状态(简化)
class EcuDiagnosticState {
public:
enum SessionType { DEFAULT_SESSION = 0x01, PROGRAMMING_SESSION = 0x02 };
enum SecurityLevel { SECURED, UNLOCKED };

SessionType currentSession = DEFAULT_SESSION;
SecurityLevel currentSecurity = SECURED;

bool isSecurityAccessAllowedForDid(uint16_t did) const {
// 模拟:DID 0x1122 是安全相关的,需要解锁
if (did == 0x1122) {
return (currentSecurity == UNLOCKED);
}
// 其他DID默认允许
return true;
}
};

// 数据标识符回调函数类型:输入DID,输出数据字节流
using DidReadCallback = std::function(uint16_t did)>;

// DCM模块
class Dcm {
public:
Dcm() {
// 注册DID及对应的读取回调
registerDid(0x1122, [this](uint16_t did) -> std::vector {
// 模拟通过RTE读取应用数据(例如发动机转速,占2字节)
uint16_t dummyEngineSpeed = 3500; // 单位RPM
return { static_cast((dummyEngineSpeed >> 8) & 0xFF),
static_cast(dummyEngineSpeed & 0xFF) };
});
registerDid(0xF190, [this](uint16_t did) -> std::vector {
// 模拟从NvM读取VIN(17字节ASCII)
std::string vin = "WDD12345678901234";
return std::vector(vin.begin(), vin.end());
});
}

// 外部调用接口:CanTp递交流程
DiagResponse processRequest(const DiagRequest& request) {
// 1. 主状态机:空闲 -> 请求处理
std::cout << "[DCM] 进入请求处理状态" << std::endl;

// 2. 服务分发:根据服务ID查找处理函数
if (request.data.empty()) {
return createNegativeResponse(0x00, 0x13); // 报文长度错误
}
uint8_t serviceId = request.data[0];
auto it = serviceHandlers.find(serviceId);
if (it == serviceHandlers.end()) {
return createNegativeResponse(serviceId, 0x11); // 服务不支持
}

// 3. 调用对应服务的处理函数
return it->second(request);
}

private:
// 服务处理函数表
std::map> serviceHandlers;

// DID回调表
std :: map < uint16_t , DidReadCallback> didCallbacks;

// ECU状态
EcuDiagnosticState diagState;

// 注册DID读取回调
void registerDid(uint16_t did, DidReadCallback callback) {
didCallbacks[did] = callback;
}

// 创建否定响应
DiagResponse createNegativeResponse(uint8_t serviceId, uint8_t nrc) {
DiagResponse resp;
resp.isPositive = false ;
resp.data = { 0x7F , serviceId, nrc };
return resp;
}

// 创建正响应(0x62服务负责拼接)
DiagResponse createPositiveResponseForReadByIdentifier(uint16_t did, const std::vector& data) {
DiagResponse resp;
resp.isPositive = true ;
resp.data.push_back( 0x62 ); // 正响应服务ID = 0x62
resp.data.push_back( static_cast < uint8_t >((did >> 8 ) & 0xFF ));
resp.data.push_back( static_cast < uint8_t >(did & 0xFF ));
resp.data.insert(resp.data.end(), data.begin(), data.end());
return resp;
}

// 服务级处理:0x22 ReadDataByIdentifier
DiagResponse handleReadDataByIdentifier(const DiagRequest& request) {
// 1. 请求格式检查(最小长度3字节)
if (request.data.size() < 3 ) {
std :: cout << "[DCM] 错误: 0x22请求长度不足" << std :: endl ;
return createNegativeResponse( 0x22 , 0x13 ); // 报文长度错误
}

// 2. 提取DID
uint16_t did = ( static_cast < uint16_t >(request.data[ 1 ]) << 8 ) | request.data[ 2 ];

// 3. 会话与安全检查
// (寻址方式简化:假设物理寻址总是需要响应,且无抑制位)
if (!diagState.isSecurityAccessAllowedForDid(did)) {
std :: cout << "[DCM] 错误: DID 0x" << std ::hex << did << " 需要解锁" << std :: endl ;
return createNegativeResponse( 0x22 , 0x33 ); // 安全访问未通过
}

// 可选:检查当前会话是否允许此服务(默认会话允许0x22,编程会话也允许,此例略)

// 4. DID有效性检查(是否已注册回调)
auto it = didCallbacks.find(did);
if (it == didCallbacks.end()) {
std :: cout << "[DCM] 错误: DID 0x" << std ::hex << did << " 未配置" << std :: endl ;
return createNegativeResponse( 0x22 , 0x31 ); // 请求超出范围
}

// 5. 调用DID级处理回调获取数据
std :: vector < uint8_t > data;
try {
data = it->second(did);
} catch (...) {
std :: cout << "[DCM] 错误: DID 0x" << std ::hex << did << " 读取失败" << std :: endl ;
return createNegativeResponse( 0x22 , 0x22 ); // 条件不满足(数据暂时不可用)
}

// 6. 构造正响应
std :: cout << "[DCM] 成功读取DID 0x" << std ::hex << did << ",数据长度=" << std ::dec << data.size() << std :: endl ;
return createPositiveResponseForReadByIdentifier(did, data);
}

// 构造函数中注册服务处理函数
void initServiceHandlers() {
serviceHandlers[ 0x22 ] = [ this ]( const DiagRequest& req) {
return handleReadDataByIdentifier(req);
};
}

public :
Dcm() {
initServiceHandlers();
}
};
5.1 使用示例

int main() {
Dcm dcm;

// 模拟物理寻址请求: 0x22 0x11 0x22
DiagRequest req;
req.data = {0x22, 0x11, 0x22};
req.isFunctionalAddress = false; // 物理寻址

DiagResponse resp = dcm.processRequest(req);
std::cout << "响应: ";
for (auto b : resp.data) {
std::cout << std::hex << (int)b << " ";
}
std::cout << std::endl;
// 预期输出正响应: 62 11 22 xx xx (xx xx为发动机转速数据)
return 0;
}

输出示例:

[DCM] 进入请求处理状态
[DCM] 错误: DID 0x1122 需要解锁
响应: 7f 22 33

若先执行安全解锁(代码中未展现,可通过31服务等实现),再次请求则可获得正响应。

6. 否定响应码(NRC)一览

NRC

含义

触发场景

0x11

ServiceNotSupported

服务ID未在服务表中注册

0x13

IncorrectMessageLength

请求报文长度不符合UDS规范

0x22

ConditionsNotCorrect

DID数据暂时不可读(如未就绪)

0x31

RequestOutOfRange

DID未配置或超出范围

0x33

SecurityAccessDenied

DID要求解锁而未解锁

0x7E

SubFunctionNotSupported

服务不支持当前会话


7. 总结与扩展

本文通过一个简化的C++ DCM实现,展示了UDS 0x22 服务的检查流程与层次化调用结构。真实AUTOSAR DCM远比此复杂,还包括:

  • 功能寻址抑制位处理 ( suppressPosRspMsgIndicationBit )

  • 多DID连续读取 ( 0x22 允许一次请求多个DID)

  • 子功能支持 (如 0x19 ReadDTCInformation 包含复杂子功能)

  • 定时器与响应超时管理

  • 安全访问算法的具体实现(seed&key)

  • 并发请求的队列处理

但核心思想是一致的:严格的请求检查 + 服务分发 + 分层处理。掌握该设计模式,很容易扩展实现 0x2E WriteDataByIdentifier、0x31 RoutineControl 等其他UDS服务。

希望本文对您理解UDS诊断软件的实现有所帮助。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
已发现10具黑人女性遗体,均为部分或完全裸体状态,多数死者身上存在明显伤痕

已发现10具黑人女性遗体,均为部分或完全裸体状态,多数死者身上存在明显伤痕

小虎新车推荐员
2026-09-27 09:10:34
快二十年过去了,那个让国人不敢扶老人的王浩法官,现在还好吗?

快二十年过去了,那个让国人不敢扶老人的王浩法官,现在还好吗?

史源观点
2026-09-27 19:00:04
张本智和罕见服输:本以为有机会夺金,但实力与林诗栋黄友政确有差距

张本智和罕见服输:本以为有机会夺金,但实力与林诗栋黄友政确有差距

念洲
2026-09-27 20:50:06
黑八预警!自由人击败山猫总分1-0 斯图尔特34+12韩旭5分2帽

黑八预警!自由人击败山猫总分1-0 斯图尔特34+12韩旭5分2帽

罗说NBA
2026-09-28 05:43:05
张本美和1-4完败痛哭,一番真心话,胜过太多找借口的运动员

张本美和1-4完败痛哭,一番真心话,胜过太多找借口的运动员

观鱼听雨
2026-09-27 23:56:42
比亚迪新车官宣:10月13日,正式上市

比亚迪新车官宣:10月13日,正式上市

科技堡垒
2026-09-26 09:16:57
中国已经成为全球第一个集体拒接电话的国家

中国已经成为全球第一个集体拒接电话的国家

黯泉
2026-06-26 10:44:35
大疆新机印上华为LOGO,9月26日起陆续到店

大疆新机印上华为LOGO,9月26日起陆续到店

硅屿手记
2026-09-26 14:31:51
港媒:大陆高铁已被“粪便淹没”!再不解决后果严重,真的假的?

港媒:大陆高铁已被“粪便淹没”!再不解决后果严重,真的假的?

铭记历史呀
2026-09-02 02:21:33
性专家说:当一个异性开口跟你要钱,要礼物,不管对方是不是想试探你的真心,你都应该明白,你已被对方列入供养者行列

性专家说:当一个异性开口跟你要钱,要礼物,不管对方是不是想试探你的真心,你都应该明白,你已被对方列入供养者行列

心理观察局
2026-08-05 06:46:04
好消息!油价或将迎来大幅下调

好消息!油价或将迎来大幅下调

沙雕小琳琳
2026-09-27 15:47:20
《兰香如故》大结局:韩梁39岁被冻死,一封遗书彻底洗白林锦岐,看懂才知兰香嫁对了人

《兰香如故》大结局:韩梁39岁被冻死,一封遗书彻底洗白林锦岐,看懂才知兰香嫁对了人

肆季娱乐
2026-09-27 23:17:19
5岁男孩腋下包块一个月疯长,疼到手臂不敢放下!多家医院无解,直到妈妈随口说了一句话

5岁男孩腋下包块一个月疯长,疼到手臂不敢放下!多家医院无解,直到妈妈随口说了一句话

环球网资讯
2026-09-27 10:52:19
葡萄牙2-1挪威!欧国联2连胜 41岁C罗替补未登场 哈兰德破门难救主

葡萄牙2-1挪威!欧国联2连胜 41岁C罗替补未登场 哈兰德破门难救主

我爱英超
2026-09-28 06:47:12
媒体透露:高市早苗在纽约劝特朗普“勿在台湾问题上顺从北京”。

媒体透露:高市早苗在纽约劝特朗普“勿在台湾问题上顺从北京”。

经点星娱
2026-09-27 12:59:00
“北京毛毛虫”冲上热搜,北京已释放7亿只小蜂治理白蛾,白蛾治理有多难?“以虫治虫”是什么原理?

“北京毛毛虫”冲上热搜,北京已释放7亿只小蜂治理白蛾,白蛾治理有多难?“以虫治虫”是什么原理?

之乎者也小鱼儿
2026-09-27 18:50:33
杭州KTV风暴余波:姑娘们抱着爱马仕排队套现,相亲圈一夜变天

杭州KTV风暴余波:姑娘们抱着爱马仕排队套现,相亲圈一夜变天

生活魔术专家
2026-09-28 03:11:22
刘欢刚离世1天,荒唐一幕就上演,吉克隽逸表态、韩磊被顶到风口

刘欢刚离世1天,荒唐一幕就上演,吉克隽逸表态、韩磊被顶到风口

往史过眼云烟
2026-09-27 19:22:32
丢人丢到国外了!49岁中国奥运冠军严重违规被查,官方:他已辞职

丢人丢到国外了!49岁中国奥运冠军严重违规被查,官方:他已辞职

二疯说球
2026-07-31 10:14:55
没想到!中国制造业的4大“草根组织”,正在掀翻全球产业链

没想到!中国制造业的4大“草根组织”,正在掀翻全球产业链

Hi科普啦
2026-09-26 19:20:15
2026-09-28 07:04:49
新能源自动驾驶 incentive-icons
新能源自动驾驶
专注于半导体行业资讯
1015文章数 348关注度
往期回顾 全部

科技要闻

星舰第14飞,为什么准备绕地球六圈?

头条要闻

孙颖莎2比4不敌王曼昱摘银 称可能等不到下届亚运会了

头条要闻

孙颖莎2比4不敌王曼昱摘银 称可能等不到下届亚运会了

体育要闻

114项指控成立,曼城已经完蛋了吗?

娱乐要闻

刘欢去世后谣言四起,韩磊被翻旧账

财经要闻

“为了看短剧,我妈两年花了22万 ”

汽车要闻

MAZDA EZ-60激光版上市 焕新全系11.39万元起

态度原创

本地
旅游
健康
公开课
军事航空

本地新闻

中秋逛白塔寺,体验国医妙荟雅集

旅游要闻

发力红色旅游带动乡亲增收(赓续长征精神奋进复兴征程·记者再走长征路)

鼻子三角区的痘,千万别乱挤!

公开课

李玫瑾:为什么性格比能力更重要?

军事要闻

特朗普"罕见"提二战中美同盟 日本慌了

无障碍浏览 进入关怀版