![]()
一、UDS 概述與定位 1.1 什么是UDS?
UDS(Unified Diagnostic Services)是ISO 14229定義的應(yīng)用層診斷協(xié)議,用于汽車電子控制單元(ECU)的故障讀取、數(shù)據(jù)通信、例程控制、軟件升級等。
1.2 UDS 與 OBD 的區(qū)別
項(xiàng)目
OBD
UDS
目的
排放相關(guān)強(qiáng)制診斷
全車ECU增強(qiáng)診斷
范圍
有限(發(fā)動機(jī)、排放)
所有ECU(BCM、GW、BMS等)
擴(kuò)展性
固定服務(wù)
支持自定義服務(wù)
網(wǎng)絡(luò)層
ISO 15765-4
ISO 15765-2(DoCAN)
1.3 DoCAN 協(xié)議棧
應(yīng)用層:UDS(ISO 14229)
網(wǎng)絡(luò)層:ISO 15765-2(多幀傳輸)
數(shù)據(jù)鏈路層:CAN(ISO 11898)
請求 :SID + SubFunction + 參數(shù)
肯定響應(yīng) :SID + 0x40 + 參數(shù)
否定響應(yīng) :0x7F + SID + NRC
請求讀取DID
0xF190:22 F1 90肯定響應(yīng):
62 F1 90 01 02 03否定響應(yīng):
7F 22 13(無效長度)
3.2 ISO 15765-2 網(wǎng)絡(luò)層簡版封裝#include
#include
#include
#include
using Byte = uint8_t;
using Bytes = std::vector ;
// UDS 服務(wù) ID(部分)
enum class UDS_SID : Byte {
DIAG_SESSION_CTRL = 0x10,
ECU_RESET = 0x11,
READ_DATA = 0x22,
WRITE_DATA = 0x2E,
SECURITY_ACCESS = 0x27,
TESTER_PRESENT = 0x3E,
ROUTINE_CTRL = 0x31,
READ_DTC = 0x19,
CLEAR_DTC = 0x14
};// NRC
enum class NRC : Byte {
OK = 0x00,
GENERAL_REJECT = 0x10,
SERVICE_NOT_SUPPORTED = 0x11,
INVALID_FORMAT = 0x13,
CONDITIONS_NOT_CORRECT = 0x22,
SECURITY_ACCESS_DENIED = 0x33,
INVALID_KEY = 0x35
};
3.3 UDS 基礎(chǔ)處理類// 幀類型
enum class N_PCI_TYPE : Byte {
SINGLE = 0x00,
FIRST = 0x10,
CONSECUTIVE = 0x20,
FLOW_CTRL = 0x30
};
// 單幀/多幀處理(簡單示例)
class DoCANTransport {
public:
static Bytes packRequest(const Bytes& udsReq) {
if (udsReq.size() <= 7) {
// 單幀
Byte pci = static_cast (N_PCI_TYPE::SINGLE) | (Byte)udsReq.size();
Bytes frame = {pci};
frame.insert(frame.end(), udsReq.begin(), udsReq.end());
return frame;
} else {
// 簡化:實(shí)際需拆分為 FF/CF/FC,此處僅示意
std::cout << "[DoCAN] Multi-frame not fully implemented\n";
return {};
}
}static Bytes unpackResponse(const Bytes& canFrame) {
if (canFrame.empty()) return {};
Byte pci = canFrame[0];
N_PCI_TYPE type = static_cast (pci & 0xF0);
if (type == N_PCI_TYPE::SINGLE) {
int len = pci & 0x0F;
return Bytes(canFrame.begin() + 1, canFrame.begin() + 1 + len);
}
// 實(shí)際需重組多幀
return {};
}
};
class UDSHandler {
private:
std::map
std
::function
const
Bytes&)>> handlers;
bool
securityLocked =
true
;
public
:
UDSHandler() {
// 注冊服務(wù)
handlers[UDS_SID::READ_DATA] = [
this
](
const
Bytes& req) {
return
handleReadData(req); };
handlers[UDS_SID::DIAG_SESSION_CTRL] = [
this
](
const
Bytes& req) {
return
handleSessionCtrl(req); };
handlers[UDS_SID::TESTER_PRESENT] = [
this
](
const
Bytes& req) {
return
handleTesterPresent(req); };
}
// 主處理入口
Bytes processRequest(const Bytes& udsReq)
{
if
(udsReq.empty())
return
buildNegativeResponse(
0x00
, NRC::GENERAL_REJECT);
Byte sid = udsReq[
0
];
UDS_SID service =
static_cast
(sid);
if
(handlers.find(service) == handlers.end()) {
return
buildNegativeResponse(sid, NRC::SERVICE_NOT_SUPPORTED);
}
return
handlers[service](udsReq);
}
private
:
// 否定響應(yīng)
Bytes buildNegativeResponse(Byte sid, NRC nrc)
{
return
{
0x7F
, sid,
static_cast
(nrc)};
}
// 肯定響應(yīng)
Bytes buildPositiveResponse(Byte sid, const Bytes& data = {})
{
Bytes resp;
resp.push_back(sid +
0x40
);
resp.insert(resp.end(), data.begin(), data.end());
return
resp;
}
// 22 讀數(shù)據(jù)
Bytes handleReadData(const Bytes& req)
{
if
(req.size() <
3
)
return
buildNegativeResponse(
0x22
, NRC::INVALID_FORMAT);
Byte didHigh = req[
1
];
Byte didLow = req[
2
];
uint16_t
did = (didHigh <<
8
) | didLow;
// 模擬數(shù)據(jù)字典
if
(did ==
0xF190
) {
return
buildPositiveResponse(
0x22
, {
0xF1
,
0x90
,
0x01
,
0x02
,
0x03
});
}
else
if
(did ==
0xF187
) {
return
buildPositiveResponse(
0x22
, {
0xF1
,
0x87
,
'V'
,
'1'
,
'.'
,
'0'
});
}
return
buildNegativeResponse(
0x22
, NRC::GENERAL_REJECT);
}
// 10 會話控制
Bytes handleSessionCtrl(const Bytes& req)
{
if
(req.size() <
2
)
return
buildNegativeResponse(
0x10
, NRC::INVALID_FORMAT);
Byte subfunc = req[
1
];
// 抑制肯定響應(yīng)檢查(bit7 = 1 時(shí)不發(fā)響應(yīng))
bool
suppressResp = (subfunc &
0x80
) !=
0
;
Byte session = subfunc &
0x7F
;
std
::
cout
<<
"[UDS] Switch to session: "
<<
std
::hex << (
int
)session <<
std
::
endl
;
if
(!suppressResp) {
return
buildPositiveResponse(
0x10
, {subfunc,
0x00
,
0x32
,
0x01
,
0xF4
});
// 仿真實(shí)例
}
return
{};
// 無響應(yīng)
}
// 3E 待機(jī)握手
Bytes handleTesterPresent(const Bytes& req)
{
bool
suppress = (req.size() >
1
) && ((req[
1
] &
0x80
) !=
0
);
if
(!suppress) {
return
buildPositiveResponse(
0x3E
, {});
}
return
{};
}
};
3.4 主程序示例(診斷請求模擬)輸出示例:int main() {
UDSHandler uds;
DoCANTransport canLayer;
// 模擬發(fā)送:22 F1 90 讀取 DID 0xF190
Bytes udsReq = {0x22, 0xF1, 0x90};
Bytes canFrame = DoCANTransport::packRequest(udsReq);
std::cout << "Send CAN: ";
for (auto b : canFrame) printf("%02X ", b);
std::cout << std::endl;
// 模擬 ECU 收到 CAN 幀,解包得到 UDS 請求
Bytes receivedUdsReq = DoCANTransport::unpackResponse(canFrame);
Bytes udsResp = uds.processRequest(receivedUdsReq);
std::cout << "UDS Response: ";
for (auto b : udsResp) printf("%02X ", b);
std::cout << std::endl;
// 測試會話切換(抑制響應(yīng))
Bytes sessionReq = {0x10, 0x83}; // subfunc 0x83 = 0x03 + 抑制bit
canFrame = DoCANTransport::packRequest(sessionReq);
receivedUdsReq = DoCANTransport::unpackResponse(canFrame);
udsResp = uds.processRequest(receivedUdsReq);
if (udsResp.empty()) {
std::cout << "[TesterPresent] No response (suppressed)" << std::endl;
}return 0;
}
Send CAN: 03 22 F1 90
UDS Response: 62 F1 90 01 02 03
[UDS] Switch to session: 3
[TesterPresent] No response (suppressed)
四、關(guān)鍵服務(wù)實(shí)現(xiàn)要點(diǎn) 4.1 $27 安全訪問(種子密鑰簡化)4.2 14 DTC 處理示例class SecureUDSHandler : public UDSHandler {
int seed = 0x1234;
int expectedKey = 0x5678; // 實(shí)際應(yīng)為算法:key = seed ^ 0x5555Bytes handleSecurityAccess(const Bytes& req) {
Byte subfunc = req[1];
if (subfunc == 0x05) { // 請求種子
return buildPositiveResponse(0x27, {0x05, (Byte)(seed >> 8), (Byte)seed});
} else if (subfunc == 0x06) { // 發(fā)送密鑰
int key = (req[2] << 8) | req[3];
if (key == expectedKey) {
securityLocked = false;
return buildPositiveResponse(0x27, {0x06});
}
return buildNegativeResponse(0x27, NRC::INVALID_KEY);
}
return buildNegativeResponse(0x27, NRC::INVALID_FORMAT);
}
};
// 簡化 DTC 讀取(按狀態(tài)掩碼 0xFF)
Bytes handleReadDTC(const Bytes& req) {
if (req.size() >= 2 && req[1] == 0x02) {
// 模擬返回 2 個(gè) DTC
return {0x59, 0x02,
0x01, 0x23, 0x45, 0x80, // DTC 1 + status
0x01, 0x67, 0x89, 0x20}; // DTC 2
}
return buildNegativeResponse(0x19, NRC::INVALID_FORMAT);
}
五、總結(jié)特性
描述
標(biāo)準(zhǔn)化
UDS 統(tǒng)一了診斷服務(wù)格式,減少重復(fù)開發(fā)
靈活性
支持自定義 DID、Routine、安全算法
可擴(kuò)展
基于 ISO 15765-2 可承載任意長度診斷數(shù)據(jù)
工程落地
現(xiàn)代汽車診斷工具(CANoe、PCAN、ZLG)均支持 UDS + DoCAN
本 C++ 示例展示了:
UDS 請求/響應(yīng)處理框架
DoCAN 單幀打包/解包
22/$3E 服務(wù)的簡化實(shí)現(xiàn)
否定響應(yīng)與抑制響應(yīng)機(jī)制
實(shí)際 ECU 開發(fā)中需完善多幀傳輸、定時(shí)管理、會話狀態(tài)機(jī)和安全訪問算法。
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺“網(wǎng)易號”用戶上傳并發(fā)布,本平臺僅提供信息存儲服務(wù)。
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.