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

UDS 服务 0x3E – TesterPresent 专业讲解与 C++ 代码示例

0
分享至


1. 服务概述

TesterPresent(0x3E)是 Unified Diagnostic Services(UDS,ISO 14229-1)中定义的一个诊断服务。该服务允许诊断仪(Tester)向 ECU 表明自己仍然在线,即使没有其他诊断请求需要发送。主要用途是保持 ECU 处于非默认会话模式(如编程会话、扩展诊断会话等),防止 ECU 因超时自动退回默认会话。

1.1 背景 – S3 Server 超时

ECU 内部有一个 S3Server 定时器。当 ECU 处于某个非默认会话模式时,该定时器会在每次收到任意诊断请求(包括 TesterPresent)后重置。如果在 S3Server 超时时间内未收到任何诊断请求,ECU 将主动退出当前非默认会话,返回至 Default Session(默认会话)。为了维持非默认会话,诊断仪必须以小于 S3Server 定时器值的周期持续发送 TesterPresent 请求。

典型 S3Server 值:5000 ms(5秒)。因此 TesterPresent 发送周期通常设为 2000~4000 ms。
2. 消息格式 2.1 请求格式

字节位置

参数名称

值(hex)

描述

0

SID

0x3E

服务标识符

1

subFunction

0x00 或 0x80

子功能:
• 0x00 – 不抑制正响应 (ECU 应返回正响应)
• 0x80 – 抑制正响应 (ECU 不发送正响应,仅执行内部操作)

注意:子功能的 bit7 为 suppressPosRspMsgIndicationBit。当该位=1(即 0x80)时,ECU 禁止发送正响应,仅更新内部定时器。这能减少总线负载。

2.2 正响应格式

仅当请求子功能的 suppressPosRspMsgIndicationBit = 0 时,ECU 返回正响应:

字节位置

参数名称

值(hex)

描述

0

Response SID

0x7E

SID + 0x40

1

subFunction

0x00 或 0x80

与请求中的子功能值相同


2.3 负响应格式

当 ECU 无法处理该服务时,返回负响应:

字节位置

参数名称

值(hex)

描述

0

Negative SID

0x7F

负响应标识符

1

SID

0x3E

产生错误的服务 ID

2

NRC

0xXX

负响应码(Negative Response Code)

常见 NRC:

  • 0x11 – 不支持该服务(未实现 0x3E)

  • 0x12 – 不支持子功能(例如请求了非 0x00/0x80 的值)

  • 0x13 – 消息长度错误

  • 0x22 – 条件不满足(例如当前会话模式不允许该操作)

  • 0x7E – 当前会话模式下子功能不支持

  • 0x7F – 服务请求序列错误

3. 时序行为

Tester                                     ECU
| |
|--[ 0x3E 0x00 ] - - - - - - - - - - - - ->|
| | 重置 S3Server 定时器
|<- - - - - - - - - [ 0x7E 0x00 ] -- -- --| (当未抑制)
| |
| (延迟 < S3Server) |
| |
|--[ 0x3E 0x80 ] - - - - - - - - - - - - ->|
| | 重置 S3Server 定时器
| | (无正响应)
| |
4. C++ 代码示例

以下代码提供了一个轻量级的 UDS 消息封装类,包含 TesterPresent 请求的构造、发送(模拟 CAN/DoIP 传输),以及响应解析。实际工程中需要替换底层通信接口(如 SocketCAN、Vector、或串口)。

#include  
          
#include
#include
#include
#include

// 诊断消息最大长度(UDS over CAN 通常 8 或 64 字节)
constexpr size_t MAX_UDS_MSG_SIZE = 64;

// 简单 UDS 消息结构
struct UdsMessage {
std::vector data;
};

// 底层通信接口(示例:模拟发送/接收,实际需替换为 CAN/以太网驱动)
class TransportLayer {
public:
// 模拟发送数据
bool send(const std::vector& rawMsg) {
std::cout << "[Tx] ";
for (auto byte : rawMsg) {
std::cout << std::hex << (int)byte << " ";
}
std::cout << std::dec << std::endl;
// 真实场景中调用 socket 或 CAN 写函数
return true;
}

// 模拟接收数据(阻塞接收,带超时)
bool receive(std::vector& buffer, int timeoutMs) {
// 此处模拟返回一个正响应
std::this_thread::sleep_for(std::chrono::milliseconds(10));
// 若已配置模拟 ECU 响应,可返回真实数据
return false; // 示例中不实际返回,改为由测试代码直接调用解析
}
};

// UDS 服务封装
class UdsClient {
public:
UdsClient(TransportLayer& transport) : m_transport(transport) {}

// 构造 TesterPresent 请求
std::vector buildTesterPresentRequest(uint8_t subFunction) {
if (subFunction != 0x00 && subFunction != 0x80) {
throw std::invalid_argument("SubFunction must be 0x00 or 0x80");
}
return {0x3E, subFunction};
}

// 发送 TesterPresent 并等待/解析响应(仅当未抑制时)
bool sendTesterPresent(uint8_t subFunction, uint8_t& responseSubFunc, uint8_t& nrc) {
auto request = buildTesterPresentRequest(subFunction);
if (!m_transport.send(request)) {
std::cerr << "发送失败" << std::endl;
return false;
}

// 如果抑制正响应,不等待响应
if ((subFunction & 0x80) != 0) {
std::cout << "正响应被抑制,无需等待 ECU 回复。" << std::endl;
return true; // 认为发送成功,但不校验 ECU 状态
}

// 否则等待正响应或负响应
std::vector response;
if (!waitForResponse(response, 200)) { // 200ms 超时
std::cerr << "等待 ECU 响应超时" << std::endl;
return false;
}

// 解析响应
if (response.size() < 2) {
std::cerr << "响应长度无效" << std::endl;
return false;
}

uint8_t respSid = response[0];
if (respSid == 0x7E) { // 正响应
responseSubFunc = response[1];
std::cout << "收到 TesterPresent 正响应,子功能 = " << std::hex << (int)responseSubFunc << std::dec << std::endl;
return true;
}
else if (respSid == 0x7F) { // 负响应
if (response.size() >= 3) {
uint8_t reqSid = response[1];
nrc = response[2];
std::cerr << "负响应: SID=0x" << std::hex << (int)reqSid
<< ", NRC=0x" << (int)nrc << std::dec << std::endl;
} else {
std::cerr << "不完整的负响应" << std::endl;
}
return false;
}
else {
std::cerr << "未知响应 SID: 0x" << std::hex << (int)respSid << std::dec << std::endl;
return false;
}
}

private:
TransportLayer& m_transport;

// 阻塞接收直到收到完整 CAN/UDS 帧或超时
bool waitForResponse(std::vector& outBuf, int timeoutMs) {
// 模拟:实际中需调用 m_transport.receive()
// 为示例完整,手工构造一个正响应(模拟 ECU 回复)
// 真实项目中请替换为真实总线读取
std::this_thread::sleep_for(std::chrono::milliseconds(10));
outBuf = {0x7E, 0x00}; // 模拟正响应
return true;
}
};

// 模拟 ECU 侧的处理函数(用于理解内部逻辑)
class EcuSimulator {
public:
// ECU 处理 TesterPresent 请求,返回响应(若未抑制)
std::vector handleTesterPresent(const std::vector& request) {
if (request.size() < 2) {
return {0x7F, 0x3E, 0x13}; // 消息长度错误
}
uint8_t subFunc = request[1];
bool suppress = (subFunc & 0x80) != 0;
bool validSubFunc = (subFunc == 0x00 || subFunc == 0x80);

if (!validSubFunc) {
return {0x7F, 0x3E, 0x12}; // 不支持子功能
}

// 重置内部 S3Server 定时器(模拟动作)
resetS3Timer();

// 如果抑制正响应,返回空
if (suppress) {
return {};
} else {
return {0x7E, subFunc}; // 正响应
}
}

private:
void resetS3Timer() {
std::cout << "[ECU] S3Server 定时器已重置" << std::endl;
}
};

// ---------- 主程序演示 ----------
int main() {
TransportLayer transport;
UdsClient client(transport);
EcuSimulator ecu; // 仅用于演示 ECU 内部行为,实际通过总线通信

std::cout << "=== TesterPresent 服务演示 ===" << std::endl;

// 场景1:正常发送,不抑制正响应
uint8_t respSub = 0;
uint8_t nrc = 0;
bool success = client.sendTesterPresent(0x00, respSub, nrc);
if (success) {
std::cout << "场景1 成功,ECU 保持在线状态。" << std::endl;
} else {
std::cout << "场景1 失败,NRC=" << std::hex << (int)nrc << std::dec << std::endl;
}

// 场景2:抑制正响应
success = client.sendTesterPresent(0x80, respSub, nrc);
if (success) {
std::cout << "场景2 成功(无响应),ECU 定时器仍被重置。" << std::endl;
}

// 场景3:周期性保持会话
std::cout << "\n--- 启动周期性 TesterPresent(周期 3000ms,抑制响应)---" << std::endl;
for (int i = 0; i < 3; ++i) {
success = client.sendTesterPresent(0x80, respSub, nrc);
if (!success) {
std::cerr << "周期性发送失败,退出" << std::endl;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
}
std::cout << "周期发送结束,ECU 若未收到请求将在 S3Server 超时后退回默认会话。" << std::endl;

return 0;
}
5. 工程注意事项
  1. 周期与超时 :TesterPresent 的发送周期必须小于 ECU 的 S3Server 参数。可通过 ReadDataByIdentifier (0x22) 读取 DID 0xF186 (S3Server 时间)获取 ECU 实际值,若无则需参考 ECU 规范(典型 5s)。

  2. 抑制正响应 :在正常周期保持中强烈推荐使用 0x80 (抑制正响应),可降低总线负载。仅在调试或需要确认 ECU 存活性时使用 0x00 。

  3. 会话切换 :TesterPresent 不会切换会话,仅维持当前会话。若要切换会话需使用 DiagnosticSessionControl (0x10) 。

  4. 安全访问 :某些 ECU 在非默认会话下可能要求先通过 SecurityAccess (0x27) 服务,否则 TesterPresent 可能返回 NRC 0x22(条件不满足)。

6. 总结

TesterPresent(0x3E)是 UDS 中维持长连接的关键服务。诊断仪通过周期发送该请求(通常抑制正响应)来阻止 ECU 超时退回到默认会话。正确实现该服务对于执行编程、例程控制或扩展诊断操作至关重要。本文提供的 C++ 示例封装了请求构造、响应解析和周期性发送逻辑,可直接集成到实际的 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.

相关推荐
热点推荐
湖南一男子拾荒21年后领得42万养老金:当过国企工人,下岗后一直未缴费以为领不到

湖南一男子拾荒21年后领得42万养老金:当过国企工人,下岗后一直未缴费以为领不到

潇湘晨报
2026-09-27 20:04:27
2-1!世界第9征服客场,新帅哈维收获首胜,23岁天才梅开二度

2-1!世界第9征服客场,新帅哈维收获首胜,23岁天才梅开二度

足球狗说
2026-09-28 01:52:53
叶一茜携女儿九寨沟出游,森碟亭亭玉立,优秀家教令人赞叹

叶一茜携女儿九寨沟出游,森碟亭亭玉立,优秀家教令人赞叹

娱你同欢
2026-09-27 17:47:39
其实很多人活不过70岁

其实很多人活不过70岁

A活着
2026-09-27 09:05:25
北口榛花绝望大哭!严子怡难以逾越,日本网友:怪物必破世界纪录

北口榛花绝望大哭!严子怡难以逾越,日本网友:怪物必破世界纪录

杨华评论
2026-09-28 02:22:51
“刘欢被去世官方紧急辟谣”,自媒体造谣还有没有底线?

“刘欢被去世官方紧急辟谣”,自媒体造谣还有没有底线?

评底郭
2026-09-27 15:56:37
确认了!她系台湾间谍情报机关人员

确认了!她系台湾间谍情报机关人员

焦作日报
2026-09-27 15:33:27
日媒:严子怡一枪砸穿日本纪录 日本网友:她去参加男子比赛也会赢

日媒:严子怡一枪砸穿日本纪录 日本网友:她去参加男子比赛也会赢

劲爆体坛
2026-09-27 23:15:02
塞尔维亚总统武契奇宣布辞职

塞尔维亚总统武契奇宣布辞职

澎湃新闻
2026-09-28 02:47:02
西贝又上热搜了,不是罗永浩,是俩探店博主线下吃出来的热度。

西贝又上热搜了,不是罗永浩,是俩探店博主线下吃出来的热度。

荆楚寰宇文枢
2026-09-27 20:53:44
全民化债的时代已经来了。

全民化债的时代已经来了。

老陆不老
2026-09-27 20:06:06
陈妤颉:100米金牌是成年礼,200米银牌是教训

陈妤颉:100米金牌是成年礼,200米银牌是教训

澎湃新闻
2026-09-27 19:53:17
全世界感叹:新的世界秩序已经形成,两个超级大国时代开启

全世界感叹:新的世界秩序已经形成,两个超级大国时代开启

农夫史记
2026-09-27 19:57:36
妻子曝刘欢真正死因!独女是诱因,错过5年抢救期,一度恶化致死

妻子曝刘欢真正死因!独女是诱因,错过5年抢救期,一度恶化致死

风月得自难寻
2026-09-27 18:01:52
亚运会女单金牌得主诞生!王曼昱4-2险胜孙颖莎,摘得生涯第2冠

亚运会女单金牌得主诞生!王曼昱4-2险胜孙颖莎,摘得生涯第2冠

乒谈
2026-09-27 20:58:07
宫鲁鸣是否下课悬念揭晓,赛后发言惹众怒,郑薇一针见血太厉害

宫鲁鸣是否下课悬念揭晓,赛后发言惹众怒,郑薇一针见血太厉害

宗介说体育
2026-09-27 19:13:06
刘欢临终细节被曝!含泪离世,老婆女儿都守在身旁,母女俩太痛苦

刘欢临终细节被曝!含泪离世,老婆女儿都守在身旁,母女俩太痛苦

观察鉴娱
2026-09-27 10:19:27
惊天警报!久明派急速夺权,克里姆林宫权力更迭已进入最后倒计时

惊天警报!久明派急速夺权,克里姆林宫权力更迭已进入最后倒计时

军情观察家
2026-09-27 22:34:40
豹纹比基尼照刷屏后,这位韩国女演员的新剧也定了

豹纹比基尼照刷屏后,这位韩国女演员的新剧也定了

浅遇时光
2026-09-27 02:25:32
吴艳妮获铜牌!媒体人:这项目在亚洲已不领先,差距非常可怕

吴艳妮获铜牌!媒体人:这项目在亚洲已不领先,差距非常可怕

奥拜尔
2026-09-27 19:45:37
2026-09-28 04:51:00
新能源自动驾驶 incentive-icons
新能源自动驾驶
专注于半导体行业资讯
1015文章数 348关注度
往期回顾 全部

科技要闻

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

头条要闻

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

头条要闻

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

体育要闻

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

娱乐要闻

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

财经要闻

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

汽车要闻

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

态度原创

教育
艺术
旅游
数码
军事航空

教育要闻

成绩靠后的老师,就该“强制”自费培训20周吗?

艺术要闻

千年松树开花,百年难遇!第一眼就惊艳了

旅游要闻

四百载风雨坚守,贵阳这座古阁,藏着贵州人的文运期许!

数码要闻

10499元 微星Claw 8 EX AI+上新:搭载Arc G3处理器、睿频可达4.6GHz

军事要闻

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

无障碍浏览 进入关怀版