![]()
一、會話模式與等級的意義 1.1 基本概念
UDS(Unified Diagnostic Services,ISO 14229)中的0x10服務用于控制ECU的診斷會話狀態。診斷會話模式本質上是一種安全機制,通過劃分不同權限等級,限制敏感診斷服務的訪問。
1.2 三種標準會話子功能
子功能
名稱
典型可用服務
0x01
Default Session(默認會話)
22讀取數據、11讀取DTC、14清除DTC、3E保活
0x02
Programming Session(編程會話)
34請求下載、36傳輸數據、37退出傳輸
0x03
Extended Session(擴展會話)
27安全訪問、2E寫入數據、31例行程序、85DTC控制
1.3 會話模式切換示意圖
┌─────────────────────────────────────────────────────────┐
│ ECU上電/復位 │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ Default Session │?──────────────────┐ │
│ │ (權限最低) │ │ │
│ └────────┬─────────┘ │ │
│ │ 10 03 │ │
│ ▼ │ 10 01
│ ┌──────────────────┐ │ │
│ │ Extended Session│ │ │
│ │ (中等級別) │ │ │
│ └────────┬─────────┘ │ │
│ │ 10 02 │ │
│ ▼ │ │
│ ┌──────────────────┐ │ │
│ │ Programming Session│──────────────────┘ │
│ │ (最高權限) │ │
│ └──────────────────┘ │
└─────────────────────────────────────────────────────────┘
二、會話模式跳轉規則 2.1 核心規則表當前會話
目標會話
是否允許
Default
Default
重新初始化默認會話
Default
Extended
停止已配置的ResponseOnEvent
Default
Programming
必須經過Extended
Extended
Default
重置所有會話相關設置
Extended
Extended
安全訪問需重新解鎖
Extended
Programming
單向跳轉
Programming
Default
重置并啟用安全鎖定
Programming
Extended
禁止反向跳轉
Programming
Programming
重新初始化編程會話
2.2 超時機制(S3保活)
Tester ECU
│ │
│──────── 10 03 (進入Extended) ─────────?│
│?─────── 50 03 (肯定響應) ─────────────│
│ │
│ (S3_client周期內) │
│──────── 3E 00 (TesterPresent) ───────?│
│?─────── 7E 00 (保活響應) ─────────────│
│ │
│ (超過S3_server時間無診斷請求) │
│ │──┐
│ │ │ 自動切回
│ │?─┘ Default
三、C++代碼實現 3.1 診斷會話管理器類定義3.2 診斷會話管理器實現// UdsSessionManager.h
#ifndef UDS_SESSION_MANAGER_H
#define UDS_SESSION_MANAGER_H
#include
#include
#include
#include
#include
namespace Uds {
// 診斷會話類型枚舉
enum class DiagnosticSession : uint8_t {
DEFAULT_SESSION = 0x01,
PROGRAMMING_SESSION = 0x02,
EXTENDED_SESSION = 0x03
};
// 服務ID枚舉
enum class ServiceId : uint8_t {
DIAGNOSTIC_SESSION_CONTROL = 0x10,
ECU_RESET = 0x11,
READ_DATA_BY_ID = 0x22,
SECURITY_ACCESS = 0x27,
COMMUNICATION_CONTROL = 0x28,
READ_DTC_INFO = 0x19,
WRITE_DATA_BY_ID = 0x2E,
ROUTINE_CONTROL = 0x31,
REQUEST_DOWNLOAD = 0x34,
TRANSFER_DATA = 0x36,
REQUEST_TRANSFER_EXIT = 0x37,
TESTER_PRESENT = 0x3E
};
// 安全訪問狀態
enum class SecurityLevel : uint8_t {
LOCKED = 0x00,
LEVEL1_UNLOCKED = 0x01,
LEVEL2_UNLOCKED = 0x02
};
// 診斷響應結構體
struct DiagnosticResponse {
uint8_t serviceId;
std::vector data;
bool success;
std::string errorMessage;
DiagnosticResponse() : success(false) {}
};
// 會話管理器類
class UdsSessionManager {
public:
using TimerCallback = std::function;
UdsSessionManager();
~UdsSessionManager();
// 核心服務處理
DiagnosticResponse handleDiagnosticSessionControl(const std::vector& request);
DiagnosticResponse handleTesterPresent(const std::vector& request);
DiagnosticResponse handleEcuReset(const std::vector& request);
// 服務訪問權限檢查
bool isServiceAllowedInCurrentSession(ServiceId serviceId) const;
// 狀態查詢
DiagnosticSession getCurrentSession() const { return currentSession_; }
SecurityLevel getSecurityLevel() const { return securityLevel_; }
bool isSessionTimedOut() const;
// 定時器管理
void updateSessionActivity();
void setS3ServerTimeout(uint32_t milliseconds);
// 非易失性數據管理(模擬)
void setVin(const std::vector& vin);
std::vector getVin() const;private:
// 會話狀態
DiagnosticSession currentSession_;
SecurityLevel securityLevel_;
// 定時器相關
uint32_t s3ServerTimeoutMs_; // S3server超時時間(默認5000ms)
std::chrono::steady_clock::time_point lastDiagnosticActivity_;
// 持久化數據(不會因會話切換而重置)
std::vector vin_; // VIN碼 (2E F1 90)
// 會話相關狀態(會話切換時可能重置)
bool responseOnEventActive_; // 0x86服務激活狀態
bool communicationControlActive_; // 0x28服務激活狀態
bool dtcControlActive_; // 0x85服務激活狀態
// 服務權限映射表
std::map std :: vector > sessionAllowedServices_;
// 跳轉規則驗證
bool canTransitionTo(DiagnosticSession target) const ;
// 會話初始化/重置
void initializeSession(DiagnosticSession session, bool isTransition) ;
void resetSessionRelatedStates() ;
void lockSecurity() ;
// 響應構造
DiagnosticResponse buildPositiveResponse(uint8_t serviceId,
const std::vector& data) ;
DiagnosticResponse buildNegativeResponse(uint8_t serviceId,
uint8_t negativeCode) ;
// 定時器檢查線程
void startSessionTimeoutMonitor() ;
void stopSessionTimeoutMonitor() ;
void sessionTimeoutHandler() ;
std :: unique_ptr < std ::thread> timeoutMonitorThread_;
bool monitorRunning_;
};
} // namespace Uds
#endif // UDS_SESSION_MANAGER_H
3.3 使用示例// UdsSessionManager.cpp
#include "UdsSessionManager.h"
#include
#include
#include
#include
#include
namespace Uds {
// NRC (Negative Response Code) 定義
namespace NRC {
constexpr uint8_t GENERAL_REJECT = 0x10;
constexpr uint8_t SERVICE_NOT_SUPPORTED = 0x11;
constexpr uint8_t SUBFUNCTION_NOT_SUPPORTED = 0x12;
constexpr uint8_t INCORRECT_MESSAGE_LENGTH = 0x13;
constexpr uint8_t CONDITIONS_NOT_CORRECT = 0x22;
constexpr uint8_t REQUEST_SEQUENCE_ERROR = 0x24;
constexpr uint8_t SECURITY_ACCESS_DENIED = 0x33;
}
UdsSessionManager::UdsSessionManager()
: currentSession_(DiagnosticSession::DEFAULT_SESSION)
, securityLevel_(SecurityLevel::LOCKED)
, s3ServerTimeoutMs_(5000) // 默認5秒
, lastDiagnosticActivity_(std::chrono::steady_clock::now())
, responseOnEventActive_(false)
, communicationControlActive_(false)
, dtcControlActive_(false)
, monitorRunning_(true)
{
// 初始化各會話允許的服務列表
// Default Session - 僅基礎診斷
sessionAllowedServices_[DiagnosticSession::DEFAULT_SESSION] = {
ServiceId::DIAGNOSTIC_SESSION_CONTROL,
ServiceId::ECU_RESET,
ServiceId::READ_DATA_BY_ID,
ServiceId::READ_DTC_INFO,
ServiceId::TESTER_PRESENT
};
// Extended Session - 高級診斷服務
sessionAllowedServices_[DiagnosticSession::EXTENDED_SESSION] = {
ServiceId::DIAGNOSTIC_SESSION_CONTROL,
ServiceId::ECU_RESET,
ServiceId::READ_DATA_BY_ID,
ServiceId::SECURITY_ACCESS,
ServiceId::COMMUNICATION_CONTROL,
ServiceId::READ_DTC_INFO,
ServiceId::WRITE_DATA_BY_ID,
ServiceId::ROUTINE_CONTROL,
ServiceId::TESTER_PRESENT
};
// Programming Session - Bootloader相關服務
sessionAllowedServices_[DiagnosticSession::PROGRAMMING_SESSION] = {
ServiceId::DIAGNOSTIC_SESSION_CONTROL,
ServiceId::ECU_RESET,
ServiceId::REQUEST_DOWNLOAD,
ServiceId::TRANSFER_DATA,
ServiceId::REQUEST_TRANSFER_EXIT,
ServiceId::TESTER_PRESENT
};
// 啟動超時監控線程
startSessionTimeoutMonitor();
}
UdsSessionManager::~UdsSessionManager() {
monitorRunning_ = false;
if (timeoutMonitorThread_ && timeoutMonitorThread_->joinable()) {
timeoutMonitorThread_->join();
}
}
//=============================================================================
// 核心服務: 0x10 診斷會話控制
//=============================================================================
DiagnosticResponse UdsSessionManager::handleDiagnosticSessionControl(
const std::vector& request)
{
DiagnosticResponse response;
// 1. 長度檢查: 至少2字節 [SID, SubFunction]
if (request.size() < 2) {
return buildNegativeResponse(static_cast(ServiceId::DIAGNOSTIC_SESSION_CONTROL),
NRC::INCORRECT_MESSAGE_LENGTH);
}
uint8_t subFunction = request[1];
// 2. 子功能有效性檢查
DiagnosticSession targetSession;
switch (subFunction) {
case 0x01: targetSession = DiagnosticSession::DEFAULT_SESSION; break;
case 0x02: targetSession = DiagnosticSession::PROGRAMMING_SESSION; break;
case 0x03: targetSession = DiagnosticSession::EXTENDED_SESSION; break;
default:
return buildNegativeResponse(static_cast(ServiceId::DIAGNOSTIC_SESSION_CONTROL),
NRC::SUBFUNCTION_NOT_SUPPORTED);
}
// 3. 跳轉規則檢查
if (!canTransitionTo(targetSession)) {
return buildNegativeResponse(static_cast(ServiceId::DIAGNOSTIC_SESSION_CONTROL),
NRC::CONDITIONS_NOT_CORRECT);
}
// 4. 記錄舊會話用于特殊處理
DiagnosticSession oldSession = currentSession_;
// 5. 執行會話切換
initializeSession(targetSession, true); // true表示這是跳轉切換
// 6. 構造肯定響應
std::vector responseData;
responseData.push_back(static_cast(targetSession));
// 可選: 添加P2/P2*定時參數(根據具體實現)
responseData.push_back(0x00); // P2 = 0ms (使用默認)
responseData.push_back(0x00); // P2* = 0ms
response = buildPositiveResponse(
static_cast(ServiceId::DIAGNOSTIC_SESSION_CONTROL),
responseData);
// 打印日志
std::cout << "[UDS] Session transition: "
<< static_cast(oldSession) << " -> "
<< static_cast(targetSession) << std::endl;
return response;
}
//=============================================================================
// 核心服務: 0x3E 保活服務
//=============================================================================
DiagnosticResponse UdsSessionManager::handleTesterPresent(
const std::vector& request)
{
DiagnosticResponse response;
// 非默認會話需要持續接收3E來維持
updateSessionActivity();
// 標準響應: 7E 00
if (request.size() >= 2 && request[1] == 0x00) {
response = buildPositiveResponse(
static_cast(ServiceId::TESTER_PRESENT),
{0x00});
} else {
response = buildPositiveResponse(
static_cast(ServiceId::TESTER_PRESENT),
{});
}
return response;
}
//=============================================================================
// 核心服務: 0x11 ECU復位
//=============================================================================
DiagnosticResponse UdsSessionManager::handleEcuReset(
const std::vector& request)
{
DiagnosticResponse response;
if (request.size() < 2) {
return buildNegativeResponse(static_cast(ServiceId::ECU_RESET),
NRC::INCORRECT_MESSAGE_LENGTH);
}
uint8_t resetType = request[1];
// 硬復位(0x01)或軟復位(0x03)后回到默認會話
if (resetType == 0x01 || resetType == 0x03) {
// 重置會話狀態
initializeSession(DiagnosticSession::DEFAULT_SESSION, true);
response = buildPositiveResponse(
static_cast(ServiceId::ECU_RESET),
{resetType});
std::cout << "[UDS] ECU Reset (type " << static_cast(resetType)
<< "), session reset to Default" << std::endl;
} else {
response = buildNegativeResponse(static_cast(ServiceId::ECU_RESET),
NRC::SUBFUNCTION_NOT_SUPPORTED);
}
return response;
}
//=============================================================================
// 權限檢查: 當前會話是否允許指定服務
//=============================================================================
bool UdsSessionManager::isServiceAllowedInCurrentSession(ServiceId serviceId) const
{
auto it = sessionAllowedServices_.find(currentSession_);
if (it == sessionAllowedServices_.end()) {
return false;
}
const auto& allowedServices = it->second;
return std::find(allowedServices.begin(), allowedServices.end(), serviceId)
!= allowedServices.end();
}
//=============================================================================
// 會話跳轉規則驗證
//=============================================================================
bool UdsSessionManager::canTransitionTo(DiagnosticSession target) const
{
// 規則1: 相同會話總是允許
if (currentSession_ == target) {
return true;
}
// 規則2: 任何會話都可以回到Default
if (target == DiagnosticSession::DEFAULT_SESSION) {
return true;
}
// 規則3: Default不能直接跳轉到Programming
if (currentSession_ == DiagnosticSession::DEFAULT_SESSION &&
target == DiagnosticSession::PROGRAMMING_SESSION) {
return false;
}
// 規則4: Programming不能跳轉到Extended
if (currentSession_ == DiagnosticSession::PROGRAMMING_SESSION &&
target == DiagnosticSession::EXTENDED_SESSION) {
return false;
}
// 規則5: Extended可以跳轉到Programming
// 規則6: Default可以跳轉到Extended
return true;
}
//=============================================================================
// 會話初始化
//=============================================================================
void UdsSessionManager::initializeSession(DiagnosticSession session, bool isTransition)
{
DiagnosticSession oldSession = currentSession_;
currentSession_ = session;
// 更新活動時間戳
updateSessionActivity();
if (!isTransition) {
// 首次啟動初始化
return;
}
// --- 根據ISO 14229定義的跳轉規則處理 ---
// 3.1 從Default到Default: 重置所有會話相關設置
if (oldSession == DiagnosticSession::DEFAULT_SESSION &&
session == DiagnosticSession::DEFAULT_SESSION) {
resetSessionRelatedStates();
// 注意: 非易失性存儲器內容(如VIN)保持不變
return;
}
// 3.2 從Default到非Default: 停止ResponseOnEvent
if (oldSession == DiagnosticSession::DEFAULT_SESSION &&
session != DiagnosticSession::DEFAULT_SESSION) {
responseOnEventActive_ = false;
// 其他狀態保持
return;
}
// 3.3 從非Default到非Default: 重新鎖定安全訪問
if (oldSession != DiagnosticSession::DEFAULT_SESSION &&
session != DiagnosticSession::DEFAULT_SESSION) {
// 安全訪問重新鎖定
lockSecurity();
// 停止ResponseOnEvent
responseOnEventActive_ = false;
// CommunicationControl和ControlDTCSetting狀態保持
// (communicationControlActive_, dtcControlActive_ 不重置)
return;
}
// 3.4 從非Default到Default: 重置所有會話相關設置
if (oldSession != DiagnosticSession::DEFAULT_SESSION &&
session == DiagnosticSession::DEFAULT_SESSION) {
resetSessionRelatedStates();
lockSecurity();
// 禁用所有非默認會話特有的功能
communicationControlActive_ = false;
dtcControlActive_ = false;
return;
}
}
//=============================================================================
// 重置會話相關狀態(不重置非易失性數據)
//=============================================================================
void UdsSessionManager::resetSessionRelatedStates()
{
responseOnEventActive_ = false;
// 周期性調度器等被禁用
// 所有OutputControl被禁用
}
//=============================================================================
// 鎖定安全訪問
//=============================================================================
void UdsSessionManager::lockSecurity()
{
securityLevel_ = SecurityLevel::LOCKED;
std::cout << "[UDS] Security locked" << std::endl;
}
//=============================================================================
// 超時管理
//=============================================================================
void UdsSessionManager::updateSessionActivity()
{
lastDiagnosticActivity_ = std::chrono::steady_clock::now();
}
bool UdsSessionManager::isSessionTimedOut() const
{
auto now = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast(
now - lastDiagnosticActivity_);
return elapsed.count() > s3ServerTimeoutMs_;
}
void UdsSessionManager::setS3ServerTimeout(uint32_t milliseconds)
{
s3ServerTimeoutMs_ = milliseconds;
}
void UdsSessionManager::startSessionTimeoutMonitor()
{
timeoutMonitorThread_ = std::make_unique([this]() {
while (monitorRunning_) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// 僅在非默認會話時檢查超時
if (currentSession_ != DiagnosticSession::DEFAULT_SESSION) {
if (isSessionTimedOut()) {
std::cout << "[UDS] Session timeout! Switching to Default" << std::endl;
initializeSession(DiagnosticSession::DEFAULT_SESSION, true);
}
}
}
});
}
//=============================================================================
// 非易失性數據管理
//=============================================================================
void UdsSessionManager::setVin(const std::vector& vin)
{
vin_ = vin;
std::cout << "[UDS] VIN written to non-volatile memory" << std::endl;
}
std::vector UdsSessionManager::getVin() const
{
return vin_;
}
//=============================================================================
// 響應構造
//=============================================================================
DiagnosticResponse UdsSessionManager::buildPositiveResponse(
uint8_t serviceId, const std::vector& data)
{
DiagnosticResponse resp;
resp.serviceId = serviceId | 0x40; // 肯定響應SID = 請求SID + 0x40
resp.data = data;
resp.success = true;
return resp;
}
DiagnosticResponse UdsSessionManager::buildNegativeResponse(
uint8_t serviceId, uint8_t negativeCode)
{
DiagnosticResponse resp;
resp.serviceId = 0x7F; // 否定響應SID
resp.data = {serviceId, negativeCode};
resp.success = false;
std::stringstream ss;
ss << "NRC: 0x" << std::hex << static_cast(negativeCode);
resp.errorMessage = ss.str();
return resp;
}} // namespace Uds
3.4 編譯與運行// main.cpp - 演示UDS 0x10服務的使用
#include "UdsSessionManager.h"
#include
#include
using namespace Uds;
void printResponse(const DiagnosticResponse& resp, const std::string& context)
{
std::cout << "\n=== " << context << " ===" << std::endl;
std::cout << "SID: 0x" << std::hex << static_cast(resp.serviceId) << std::endl;
if (!resp.data.empty()) {
std::cout << "Data: ";
for (uint8_t byte : resp.data) {
std::cout << "0x" << std::hex << std::setw(2) << std::setfill('0')
<< static_cast(byte) << " ";
}
std::cout << std::endl;
}
if (resp.success) {
std::cout << "Status: SUCCESS" << std::endl;
} else {
std::cout << "Status: FAILED - " << resp.errorMessage << std::endl;
}
}int main()
{
UdsSessionManager ecu;
std::cout << "========== UDS 0x10 Diagnostic Session Control Demo ==========" << std::endl;
// 1. 查詢初始狀態
std::cout << "\n[Initial] Session: "
<< static_cast(ecu.getCurrentSession())
<< " (Default)" << std::endl;
// 2. Default -> Extended (合法)
auto resp1 = ecu.handleDiagnosticSessionControl({0x10, 0x03});
printResponse(resp1, "Default -> Extended (10 03)");
// 驗證服務權限
std::cout << "2E (WriteData) allowed in Extended? "
<< ecu.isServiceAllowedInCurrentSession(ServiceId::WRITE_DATA_BY_ID)
<< std::endl;
// 3. Extended -> Programming (合法)
auto resp2 = ecu.handleDiagnosticSessionControl({0x10, 0x02});
printResponse(resp2, "Extended -> Programming (10 02)");
// 驗證編程服務權限
std::cout << "34 (RequestDownload) allowed in Programming? "
<< ecu.isServiceAllowedInCurrentSession(ServiceId::REQUEST_DOWNLOAD)
<< std::endl;
std::cout << "2E (WriteData) allowed in Programming? "
<< ecu.isServiceAllowedInCurrentSession(ServiceId::WRITE_DATA_BY_ID)
<< std::endl;
// 4. Programming -> Extended (非法 - 應被拒絕)
auto resp3 = ecu.handleDiagnosticSessionControl({0x10, 0x03});
printResponse(resp3, "Programming -> Extended (10 03) [SHOULD FAIL]");
// 5. Programming -> Default (合法)
auto resp4 = ecu.handleDiagnosticSessionControl({0x10, 0x01});
printResponse(resp4, "Programming -> Default (10 01)");
// 6. Default -> Programming (非法 - 必須經過Extended)
auto resp5 = ecu.handleDiagnosticSessionControl({0x10, 0x02});
printResponse(resp5, "Default -> Programming (10 02) [SHOULD FAIL]");
// 7. 重新進入Extended,演示3E保活
ecu.handleDiagnosticSessionControl({0x10, 0x03});
std::cout << "\n[Extended Session Active] Sending TesterPresent..." << std::endl;
for (int i = 0; i < 3; i++) {
auto resp6 = ecu.handleTesterPresent({0x3E, 0x00});
std::cout << "3E #" << (i+1) << " response: 0x" << std::hex
<< static_cast(resp6.serviceId) << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
// 8. 模擬超時(設置短超時用于演示)
ecu.setS3ServerTimeout(2000); // 2秒超時
std::cout << "\n[Timeout Demo] Waiting 3 seconds without diagnostic request..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout << "Session after timeout: "
<< static_cast(ecu.getCurrentSession())
<< " (should be Default)" << std::endl;
// 9. 演示非易失性數據持久化
std::cout << "\n[Persistence Demo] Writing VIN to NVM..." << std::endl;
ecu.setVin({'W','V','W','Z','Z','Z','1','Z','Z','1','2','3','4','5','6','7','8'});
// 切換到不同會話再回來
ecu.handleDiagnosticSessionControl({0x10, 0x03});
ecu.handleDiagnosticSessionControl({0x10, 0x01});
auto vin = ecu.getVin();
std::cout << "VIN after session cycle: ";
for (uint8_t c : vin) std::cout << static_cast(c);
std::cout << " (preserved!)" << std::endl;
return 0;
}
四、關鍵要點總結# 編譯命令
g++ -std=c++17 -pthread UdsSessionManager.cpp main.cpp -o uds_demo# 運行
./uds_demo
要點
安全機制
高權限服務需要先切換到對應會話并完成安全解鎖
跳轉路徑
Default → Extended → Programming(單向)
超時保活
非默認會話需周期性發送3E,否則自動切回Default
安全鎖定
會話切換時安全訪問狀態會被重置(除非規則明確要求保持)
狀態保持
CommunicationControl和ControlDTCSetting在非默認會話間切換時保持
持久化
NVM寫入的數據(如VIN)不受會話切換影響
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
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.