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

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.

相关推荐
热点推荐
张雪一句“鄙视你”,泰康秒赔8万:他不是突然良心发现,而是突然发现“不要脸的成本”太高了

张雪一句“鄙视你”,泰康秒赔8万:他不是突然良心发现,而是突然发现“不要脸的成本”太高了

迷世书童
2026-09-27 10:52:03
医院老护士含泪揭秘:人临终前的10个残酷真相,很多子女不懂

医院老护士含泪揭秘:人临终前的10个残酷真相,很多子女不懂

蝉吟槐蕊
2026-09-13 18:15:04
25岁女子吐槽河北婆婆做“糊弄饭”,老公不耐烦了:爱吃吃不吃滚

25岁女子吐槽河北婆婆做“糊弄饭”,老公不耐烦了:爱吃吃不吃滚

许三岁
2026-09-28 02:00:08
小布披露绝望输球内幕下周取代吴易昺,王左亚运血案含金量引热议

小布披露绝望输球内幕下周取代吴易昺,王左亚运血案含金量引热议

网球之家
2026-09-28 10:27:54
低价“0公里二手车”连环骗局爆雷,上千车主或面临钱车两空

低价“0公里二手车”连环骗局爆雷,上千车主或面临钱车两空

凤凰网财经
2026-09-27 22:01:48
4次扑救哈兰德+非常规手型!科斯塔9.4分,葡萄牙换代成功了

4次扑救哈兰德+非常规手型!科斯塔9.4分,葡萄牙换代成功了

赵或是个热血青年
2026-09-28 11:28:49
西方不服气,为何中国没发动任何战争,却成为世界一流经济强国

西方不服气,为何中国没发动任何战争,却成为世界一流经济强国

纪史行者
2026-09-28 08:33:10
刘欢临终细节被曝!含泪离世,老婆女儿都守在身旁,母女俩太痛苦

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

观察鉴娱
2026-09-27 10:19:27
张杰谢娜一家五口出游,仨女儿都坐推车不带腿,有专属摄影师摄像

张杰谢娜一家五口出游,仨女儿都坐推车不带腿,有专属摄影师摄像

阿废冷眼观察所
2026-09-28 00:02:06
喜讯!U23国足进入亚运会四强之后,足协就可能跟多位强援完成续约

喜讯!U23国足进入亚运会四强之后,足协就可能跟多位强援完成续约

振刚说足球
2026-09-28 10:05:42
亚运会女单金牌得主诞生!王曼昱4-2险胜孙颖莎,摘得生涯第2冠

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

乒谈
2026-09-27 20:58:07
彻底崩盘!曼联 6000 万水货混日子!名宿怒喷卡里克赶紧清洗

彻底崩盘!曼联 6000 万水货混日子!名宿怒喷卡里克赶紧清洗

澜归序
2026-09-28 09:11:57
人无法共情以前自己买的那些东西。网友:三个垃圾桶1700。

人无法共情以前自己买的那些东西。网友:三个垃圾桶1700。

天气观察站
2026-09-27 16:03:26
气愤!刘翔师弟夺冠后怒斥:日本电视台没把我当回事 日本选手无视我

气愤!刘翔师弟夺冠后怒斥:日本电视台没把我当回事 日本选手无视我

念洲
2026-09-27 20:49:20
李谷一不再隐瞒,揭晓宋祖英走上高位的真相,观众:原来如此!

李谷一不再隐瞒,揭晓宋祖英走上高位的真相,观众:原来如此!

林轻吟
2026-07-02 19:19:19
中秋假期游客在秦皇岛乘坐海上索道被淋成落汤鸡,景区:下雨后暂停了一会索道,淋到雨的游客是在下雨前上去的

中秋假期游客在秦皇岛乘坐海上索道被淋成落汤鸡,景区:下雨后暂停了一会索道,淋到雨的游客是在下雨前上去的

台州交通广播
2026-09-27 19:31:25
一投提前下班!严子怡大幅提升赛会纪录,夺亚运会女子标枪金牌

一投提前下班!严子怡大幅提升赛会纪录,夺亚运会女子标枪金牌

全景体育V
2026-09-27 21:01:43
如果莉莉贝特真长这样!丝毫不输夏洛特公主,皮肤还更白嫩!

如果莉莉贝特真长这样!丝毫不输夏洛特公主,皮肤还更白嫩!

艺利森
2026-09-28 09:07:46
美方同意放行伊朗总统,专机起飞后怕生变故,全程未在第三国停靠

美方同意放行伊朗总统,专机起飞后怕生变故,全程未在第三国停靠

你是我心中最美星空
2026-09-27 20:36:09
案例:湖南女护士被执行死刑,行刑时回头质问武警,让他当场崩溃

案例:湖南女护士被执行死刑,行刑时回头质问武警,让他当场崩溃

星宇共鸣
2025-09-17 17:58:03
2026-09-28 12:08:49
新能源自动驾驶 incentive-icons
新能源自动驾驶
专注于半导体行业资讯
1015文章数 348关注度
往期回顾 全部

科技要闻

智能体惹了多少祸,OpenAI自己没查清!

头条要闻

媒体:俄杜马选举普京获压倒性胜利 俄乌冲突有2大走向

头条要闻

媒体:俄杜马选举普京获压倒性胜利 俄乌冲突有2大走向

体育要闻

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

娱乐要闻

好汉刘欢:一副好嗓子,一颗赤子心

财经要闻

标价298元核桃油, 实为大豆油冒充

汽车要闻

神龙科技与Momenta达成全球战略合作 2027年起推新车

态度原创

房产
时尚
教育
健康
公开课

房产要闻

全年霸榜TOP1!南海・叁號院周年官宣:新作即将登场

女人过了三四十岁,一定要准备一件小西装,大方得体又显瘦

教育要闻

官宣!成都启动学区制治理改革

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

公开课

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

无障碍浏览 进入关怀版