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

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-28 09:06:08
洛夫顿离开上海得不偿失!发文开启勿扰模式,重返大鲨鱼障碍重重

洛夫顿离开上海得不偿失!发文开启勿扰模式,重返大鲨鱼障碍重重

体育见习官
2026-09-28 07:58:50
时隔两年半冲突视频曝光!斯图尔特挥拳尤班克斯 曾因此被禁赛3场

时隔两年半冲突视频曝光!斯图尔特挥拳尤班克斯 曾因此被禁赛3场

罗说NBA
2026-09-28 06:21:57
曼联无意让卡里克下课,重用拉什福德起作用!聘拉爵心仪主帅需1500万

曼联无意让卡里克下课,重用拉什福德起作用!聘拉爵心仪主帅需1500万

罗米的曼联博客
2026-09-28 10:14:03
CBA速递,上海大鲨鱼锁定麦基,六十万美元非常平价,三剑客浮现

CBA速递,上海大鲨鱼锁定麦基,六十万美元非常平价,三剑客浮现

体坛小快灵
2026-09-28 08:43:41
“升糖直接爆了”,家长晒儿子上学早餐,网友:吃完了倒头就睡

“升糖直接爆了”,家长晒儿子上学早餐,网友:吃完了倒头就睡

泽泽先生
2026-09-21 13:37:01
刘欢病逝2天,别墅、版权收入等资产曝光,遗产分配成焦点

刘欢病逝2天,别墅、版权收入等资产曝光,遗产分配成焦点

往史过眼云烟
2026-09-27 16:40:27
儿子作文里写:“我爸爸妈妈从来不吵架,但他们也不怎么说话”

儿子作文里写:“我爸爸妈妈从来不吵架,但他们也不怎么说话”

自由心向往之
2026-09-25 08:30:13
拒绝网红脸!央视秋晚四美火出圈,观众:这才是真审美

拒绝网红脸!央视秋晚四美火出圈,观众:这才是真审美

阿废冷眼观察所
2026-09-27 12:56:52
国家统计局:2026年1—8月份全国规模以上工业企业利润增长15.7%

国家统计局:2026年1—8月份全国规模以上工业企业利润增长15.7%

界面新闻
2026-09-28 09:31:49
台湾提出和统条件:一国三制,“外交权”和拥有军队?是痴心妄想

台湾提出和统条件:一国三制,“外交权”和拥有军队?是痴心妄想

老头的传奇色彩
2026-08-06 17:59:31
广州一工人误踩8层自建房楼顶绿色帆布坠入电梯井,连破两道安全网跌至一楼,调查报告披露:承包人无资质冒用他人名义,未设警示标志

广州一工人误踩8层自建房楼顶绿色帆布坠入电梯井,连破两道安全网跌至一楼,调查报告披露:承包人无资质冒用他人名义,未设警示标志

扬子晚报
2026-09-28 10:35:00
红薯正大量上市!研究发现:糖尿病吃一次红薯,等于给血糖添堵?

红薯正大量上市!研究发现:糖尿病吃一次红薯,等于给血糖添堵?

老李讲健康
2026-09-28 07:30:07
“磨膝大户”被揪出,是跑步的20倍,医生:不想软骨磨光,早扔掉

“磨膝大户”被揪出,是跑步的20倍,医生:不想软骨磨光,早扔掉

看世界的人
2026-09-20 22:04:47
王思聪坐香奈儿VIP贵宾室,懒懒旁边试包,消费降级传闻又被打脸

王思聪坐香奈儿VIP贵宾室,懒懒旁边试包,消费降级传闻又被打脸

梦醉为红颜一笑
2026-09-27 14:27:39
骁龙8EE6+11000mAh!荣耀新机官宣,9月28日发布

骁龙8EE6+11000mAh!荣耀新机官宣,9月28日发布

科技堡垒
2026-09-28 10:19:38
“抱歉,我们不喜欢肥头大耳的”,女孩公开追求体制内男,面相输了

“抱歉,我们不喜欢肥头大耳的”,女孩公开追求体制内男,面相输了

世界圈
2026-08-15 10:29:14
新央企首任董事长,未公布被调查就直接“双开”

新央企首任董事长,未公布被调查就直接“双开”

评论员岳连
2026-09-27 20:54:46
一个国家能蠢到什么程度?看看法国就明白了:法国黑人接近800万,巴黎新生儿里70%是黑人

一个国家能蠢到什么程度?看看法国就明白了:法国黑人接近800万,巴黎新生儿里70%是黑人

怪味历史连连看
2026-09-08 01:55:32
越老越妖,梅西30岁后罚进43粒直接任意球,比30岁前多10粒

越老越妖,梅西30岁后罚进43粒直接任意球,比30岁前多10粒

懂球帝
2026-09-28 10:05:05
2026-09-28 11:35:00
新能源自动驾驶 incentive-icons
新能源自动驾驶
专注于半导体行业资讯
1015文章数 348关注度
往期回顾 全部

科技要闻

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

头条要闻

牛弹琴:内塔尼亚胡有大麻烦了 不是命硬就能扛过去的

头条要闻

牛弹琴:内塔尼亚胡有大麻烦了 不是命硬就能扛过去的

体育要闻

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

娱乐要闻

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

财经要闻

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

汽车要闻

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

态度原创

亲子
房产
手机
游戏
公开课

亲子要闻

江苏产妇产下5斤9两男宝,脐带刚剪断,宝宝突然刺耳尖叫

房产要闻

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

手机要闻

涨价了照样买 iPhone 18 Pro系列国内销量上涨

星际争霸新游已经"可以玩"了!亲身感受刺蛇爆头

公开课

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

无障碍浏览 进入关怀版