UDS由ISO-14229系列標准定義,ISO 14229-1 定義了診斷服務,不涉及網絡及實現,只有應用層的內容。而ISO 14229-3則定義了UDS在CAN總線上的實現。
診斷通信的過程從用戶角度來看非常容易理解,診斷儀發送診斷請求(request),ECU給出診斷響應(response),而UDS就是為不同的診斷功能的request和response定義了統一的內容和格式。
最近關於UDS的一系列專欄文章只關注應用層的診斷服務,忽略下層的通信機制。
Diagnostic request的格式:
Diagnostic request的格式可以分為兩類:一類是擁有sub-function的,另一類是沒有sub-function的,如下面兩張圖所示。Service ID(以下簡稱SID)的長度固定為1個字節,代表了這條診斷命令執行的什么功能。sub-function的長度也是1個字節,它通常表示對這個診斷服務的具體操作,比如是啟動、停止還是查詢這個診斷服務。而后面的parameter則根據各個診斷服務的不同具有不同的內容,長度和格式並沒有統一規格,它用於限定診斷服務執行的條件,比如某個診斷服務執行的時間等。parameter的一個重要應用是作為標識符,標識診斷請求要讀出的數據內容,我會在后續的文章里詳細講述各個診斷服務的應用。
擁有sub-function的診斷請求
無sub-function的診斷請求
有一點要補充的是,其實sub-function嚴格來說是7個bit,而不是1個byte,因為它的最高位bit被用於抑制正響應(suppress positive response,SPR),如果這個bit被置1,則ECU不會給出正響應(positive response); 如果這個bit被置0,則ECU會給出正響應。這樣做的目的是可以告訴ECU不要發不必要的response,從而節約通信資源。
Diagnostic response的格式:
Diagnostic response分為positive和negative兩類。positive response意味着診斷儀發過來的診斷請求被執行了,而negative response則意味着ECU因為某種原因無法執行診斷儀發過來的診斷請求,而無法執行的原因則存在於negative response的報文中。
positive response
positive response的格式如上圖所示,也基本上是由三部分組成,其中的response SID這個字節作為診斷請求的echo,它等於SID + 0X40。后面的兩個部分則視具體的診斷服務而定。
negative response
negative response的格式固定為3個字節,第一個字節為0x7F,第二個字節是被拒絕掉的SID,第三個字節是這個診斷服務無法被執行的原因。下面這張圖列舉了部分原因代碼,比如,如果ECU給出7F 22 13這個negative response,則說明22這個服務因為診斷請求數據長度不對的原因無法執行。
Negative Response Code
總結:診斷通信的過程就是診斷儀和ECU交換數據,前者發的是request,后者發的是response,而UDS最重要的作用就是定義了這些request和response的格式和內容。今天這篇文章對request和response進行了簡要介紹,在后面描述各種診斷服務的文章中我會通過更多的示例來說明這兩個基本概念。
UDS定義的診斷服務從邏輯來說分為以下幾類:
- Diagnostic and Communication Management (診斷和通信管理)
- Data Transmission (數據傳輸)
- Stored Data Transmission (存儲數據傳輸,用於操作DTC)
- InputOutput Control (IO控制)
- Routine Control (不知如何翻譯好,作用是調用ECU內部的預置函數)
- Upload Download (上傳下載)
UDS規定使用1個byte來表示診斷服務,即所謂的Service ID,簡稱SID。本文介紹一下Diagnostic and Communication Management 這一類診斷服務中的一部分。
DiagnosticSessionControl (0x10)
DiagnosticSessionControl診斷request的格式
DiagnosticSessionControl這個服務的SID是0x10,request固定為2個byte,第一個byte是SID,第二個byte的低7bit是sub-function,用於指示ECU將進入的session。UDS定義的session包括:
0x00 ISOSAEReserved(保留)
0x01 defaultSession
0x02 ProgrammingSession
0x03 extendedDiagnosticSession
0x04 safetySystemDiagnosticSession
0x05 – 0x3F ISOSAEReserved(保留)
0x40 – 0x5F vehicleManufacturerSpecific(由整車廠自定義使用)
0x60 – 0x7E systemSupplierSpecific(由ECU供應商自定義使用)
0x7F ISOSAEReserved(保留)
DiagnosticSessionControl用於控制ECU在不同的session之間進行轉換,session可以看作是ECU所處的一種軟件狀態,在不同的session中診斷服務執行的權限不同。 ECU上電之后,默認處在defaultSession中,在這個session中很多診斷服務不可以執行,很多診斷相關的數據不能讀取或寫入。一般的診斷儀啟動之后,會給ECU發送10 03,即讓ECU進入 extendedDiagnosticSession中,在這個session中可執行的診斷服務就很多了。而如果要讓ECU保持在non-defaultSession中,則需要診斷儀每隔固定的時間發送0x3E服務,ECU才會知道診斷儀有和自己通信的需求,從而保持在non-defaultSession中。另一個常用的session是ProgrammingSession,在這個session中可以進行軟件刷寫的一系列診斷服務。0x40 – 0x5F 這個范圍中的session由整車廠自定義使用,比如,某些診斷服務或診斷數據的操作需要在生產線上執行,即所謂的End-Of-Line,整車廠可以從這個范圍中選擇一個值來表示EOL session;又或者在開發階段需要某種“超級”session,則也可以從這里選一個值用來使ECU進入開發模式的session。DiagnosticSessionControl這個服務非常簡單,但是它卻是ECU和診斷通信的第一條診斷命令。
DiagnosticSessionControl診斷response的格式
這個診斷服務的response分為三部分,第一部分是0x50,作為SID的echo;第二部分是進入的session,作為sub-function的echo;第三部分是4個字節,前兩個字節代表P2Server_max,即ECU在應用層上對診斷命令的響應時間,后兩個字節代表P2*Server_max
,即ECU在暫時無法處理當前診斷命令(具體表現為發送了NRC 0X78),在應用層上對診斷命令響應的最長時間。
ECUReset (0x11)
ECUReset 這條指令的用途是通過診斷請求使ECU重啟。
ECUReset 診斷request的格式
ECUReset 這個服務的SID是0x11,request固定為2個byte,第一個byte是SID,第二個byte的低7bit是sub-function,用於指示ECU將模擬哪種方式進行重啟。
常用的sub-function包括(只舉2個例子,UDS還定義了很多其他的值)
0x01 hardReset 模擬KL30的重啟
0x02 keyOffOnReset 模擬KL15的重啟
當我們通過診斷命令改寫了ECU的某些數據,或者對ECU進行了某些設置,只有將ECU重啟才能將這些配置生效,所以就有了這個診斷命令。在ECUReset 執行之后,ECU會從Non-defaultsession回退到defaultsession中。
SecurityAccess (0x27)
廠家可能會為ECU定義某些安全級別稍微高一些的診斷服務,在執行此類服務之前,就需要執行SecurityAccess 這個診斷命令,進行一個簡單的身份驗證。
完成SecurityAccess 有以下步驟:
- 診斷儀向ECU請求“Seed”(通常是一個與時間相關的偽隨機數),
- ECU向診斷儀發送“Seed”,
- 診斷儀向ECU發送“Key” (根據請求得到的Seed和一個本地的密碼進行計算得來)
- ECU判斷診斷儀發來的“Key”是否有效
根據UDS的定義,0x03, 0x05, 0x07 – 0x41 這個范圍留給用於requestSeed的sub-function;0x04, 0x06, 0x08 – 0x42這個范圍留給用於sendKey的sub-function。具體選擇哪對值,由整車廠自己定義。整車廠也可以選擇多對sub-function,用於不同等級的安全訪問。
下面我舉一個完成SecurityAccess的診斷命令的例子,假設0x05用於requestSeed,0x06用於sendKey。
診斷儀發送 27 05
ECU響應 67 05 01 01 01(seed是 01 01 01)
診斷儀發送 27 06 02 03 04(key值是02 03 04,seed是 01 01 01,假設本地密碼為01 02 03,而算法就是將密碼與seed相加)
ECU驗證成功 67 06
此時ECU就處於unlocked的狀態了,那些被保護起來的診斷服務和診斷數據可以被操作了。通常來說,如果ECU重啟,或者回到了default session,unlocked狀態就失效了,如果要執行相關診斷服務,則需要再次執行上面描述的過程。
CommunicationControl (0x28)
該服務用於打開/關閉某些類別的報文的發送/接收。它通常在刷寫軟件或大量數據的時候使用,因為在刷軟件或參數的時候並不需要ECU進行與通信相關的功能,將通信關閉之后可以把所有通信資源都留給軟件或參數的下載,當下載過程完成之后再利用該服務將通信恢復即可。
0x28服務的格式如下圖所示
0x28服務的格式
第一部分即SID,一個byte,值為0x28;
第二部分是sub-function,表明要對ECU的通信進行哪種控制,具體包括 :
0x00 enableRxAndTx (激活接收和發送)
0x01 enableRxAndDisableTx(激活接收和關閉發送)
0x02 disableRxAndEnableTx(激活發送和關閉接收)
0x03 disableRxAndTx(關閉接收和發送)
0x04 enableRxAndDisableTxWithEnhancedAddressInformation(激活接收和關閉發送,針對特定的地址)
0x05 enableRxAndTxWithEnhancedAddressInformation(激活接收和發送,針對特定的地址)
0x06 - 0x7F都是保留或者留給廠商自定義的。
第三部分表明這條診斷請求要對哪種報文進行控制,長度為1個byte,定義如下表所示:
communicationType的定義
這個byte中最常用的就是低2 bit,0x1代表普通應用報文,0x2代表網絡管理報文,0x3代表普通應用報文和網絡管理報文。
第四部分是optional的,只有當sub-functional等於0x04或0x05時才需要使用。
舉個完整的診斷服務例子:
28 01 01 表示激活應用報文的接收並關閉應用報文的發送(網絡管理報文不受影響)。
28 00 01 表示激活應用報文的接收和發送(網絡管理報文不受影響)。
TesterPresent (0x3E)
這個診斷服務的用處可以通過它的名字很明顯地得知,即告知ECU診斷儀還在連接着。在上一篇文章中我說到了關於session的部分,如果沒有診斷命令的發送和接收,ECU將從non-default session中回退到default session, 0x3E就是用於使ECU保持在當前session。
這應該是UDS中最簡單的一個診斷服務了,它永遠只有兩個byte,格式如下:
0x3E診斷服務的格式
當sub-function是0x00時,ECU要給出response;當sub-function是0x80時,ECU不需要要給出response。
一般來說主機廠會為這個服務定義兩個時間參數,一個參數用於規定自己的診斷儀發送0x3E服務的間隔,另一個參數用於定義ECU收不到0x3E服務的timeout時間。
ControlDTCSetting (0x85)
該服務用於控制ECU的DTC存儲,這個服務常常和前面提到的28服務一起使用,比如,在開始寫參數之前,為了獲得更快的傳輸速度,我們用28服務把所有ECU的通信關閉了,但此時因為收到不到相關的報文,ECU會沒有必要地存儲很多DTC,這時如果我們使用85服務把ECU存儲DTC的功能暫時性地禁止掉,則不會造成這種麻煩。
0x85服務的格式
第一部分即SID,一個byte,值為0x85;
第二部分是sub-function,表明是打開還是關閉ECU的DTC存儲,具體包括 :
0x01 on
0x02 off
第三部分是optional的,由各家自己定義,比如,可以用FF FF FF 來表示這條診斷命令針對所有的DTC。
ResponseOnEvent (0x86)
我在以前的文章里說,診斷通信過程是問答式的,診斷儀發請求,ECU給響應。0x86服務算是一個例外,在ECU收到這條0x86服務之后,當DTC產生時,它會自動地上報DTC及相關環境數據,直到用另一條0x86服務來關閉ECU的這個行為。
該功能主要用於ECU的前期開發階段,在售后和生產中是不會用到的,而且該服務的格式復雜(即可變的參數很多),執行它還分為好幾個步驟,我就不詳細寫了。
LinkControl (0x87)
這個服務用於轉化ECU數據鏈路層和物理層的狀態,比如,在高速CAN上的ECU正常通信速率是500 kbit/s,但它同時也支持1M bit/s的波特率,如果需要刷寫大量數據,便可以利用這條診斷服務讓ECU以1M bit/s的波特率進行通信。
這個診斷服務的執行分為兩個步驟:
- 驗證ECU是否支持要調整到的目標波特率
- 讓ECU的數據鏈路層和物理層轉到目標波特率的通信狀態
只有當第一個步驟驗證通過了,第二個步驟才可以成功執行。
這篇文章介紹一下UDS的第二類診斷服務,即Data Transmission (數據傳輸)。這類診斷服務包括以下SID:
ReadDataByIdentifier (0x22)
ReadMemoryByAddress (0x23)
ReadScalingDataByIdentifier (0x24)
ReadDataByPeriodicIdentifier (0x2A)
DynamicallyDefineDataIdentifier (0x2C)
WriteDataByIdentifier (0x2E)
WriteMemoryByAddress (0x3D)
通常,0x22和0x2E成對使用,0x23和0x3D成對使用,這幾個服務用於診斷數據的基本讀寫操作。0x24,0x2A,0x2C是一些特殊操作。
0x22和0x2E這兩個服務是對以標識符(identifier)標記的數據的操作,前者是讀,后者是寫。UDS規定,診斷數據使用兩個byte的標識符來標記,比如,0xF187用來標記ECU的零件號,0xF19E用於標記該ECU所使用的診斷文件的名字,UDS還規定了廠家可以自定義的標識符范圍。這兩個服務的用法很簡單,下面我以讀取ECU的零件號為例說明:
22 F1 87 (讀取零件號)
62 F1 87 XX YY ZZ KK MM NN(給出零件號)
具體每次可以使用22服務讀取幾個ID,每個ID的讀寫權限(比如在哪些session中可以讀寫,是否需要安全訪問操作等),由廠家自定義。假設零件號這個ID是可以寫入的話,則寫零件號的診斷命令是:
2E F1 87 XX YY ZZ KK MM NN(寫入零件號)
6E F1 87(給出positive response)
0x23和0x3D這兩個服務是對以地址信息(memoryAddress )標記的數據的操作,前者是讀,后者是寫。這個命令的格式稍微復雜一點。以0x23為例,它的診斷請求格式是:
0x23服務的請求格式0x23
第一部分固定為1個byte, 0x23;
第二部分是格式信息,長度為1個byte,高4 bits用於指示memorySize的長度(字節數),低4 bits用於指示memoryAddress的長度(字節數)。比如,如果這個值為0x46,則后面的memorySize為6個byte,memoryAddress為4個byte。
第三部分是memoryAddress信息,它的長度由第二部分的AddressAndLengthFormatIdentifier指示。
第四部分是memorySize信息,它的長度由第二部分的AddressAndLengthFormatIdentifier指示。
如果這條命令的格式是 23 22 xx yy aa bb,則它的含義就是,讀取xx yy地址的長度為aa bb的數據。
了解了0x23的用法,0x3D的用法就很好理解了,它標識memoryAddress和memorySize的方法與0x23相同,只是在診斷命令最后再加上一段需要寫入的數據。
這篇文章介紹Stored Data Transmission (存儲數據傳輸,用於操作DTC)這一類診斷服務,涉及到兩條診斷命令,分別是:
0x14:ClearDiagnosticInformation
0x19:ReadDTCInformation
這兩條服務用於操作存儲在ECU中的DTC,使用頻率很高,而且它們比較好地體現了“診斷”兩個字的含義。
0x14:ClearDiagnosticInformation
這條診斷命令的格式比較簡單,用法也很好理解,即刪除存儲在ECU中的DTC。
0x14診斷命令請求的格式
第一個字節就是SID了,后邊的三個字節用於標識將要被刪除的DTC種類,UDS規定用FF FF FF表示所有種類的DTC,由廠家自定義代表Powertrain、Chassis、、Body、Network Communication等種類DTC的值。
比如,14 FF FF FF這條指令表示的就是刪除掉ECU中的所有DTC。ECU只需要返回一個0x54表示成功執行即可。
0x19:ReadDTCInformation
這條指令用於讀取存儲在ECU中的DTC,它的格式如下
0x19診斷命令請求的格式0x14診斷命令請求的格式
0x19服務的sub-function代表了各式各樣讀取DTC的方法,UDS給19服務的sub-function從0x00到0x19進行了明確定義,我只使用過其中4種,下面對我用過的這些進行介紹,如果大家對其他的感興趣,可以查閱ISO 14229的定義。
sub-function = 0x01 (reportNumberOfDTCByStatusMask)
sub-function = 0x01用於讀取符合特定條件的DTC數量,此時parameter為一個byte的Mask,用於與DTC的Status進行“與”運算,而ECU返回的則是"與"運算之后結果不為0的DTC的數量。DTC的Status用一個byte表示,其中的8個bit分別代表DTC的不同狀態,比如,bit 0 表示這個DTC是active的還是passive的,bit 4表示這個DTC是否已經被confirm了,如果DTC的狀態是confirm,則說明該DTC已經被ECU存儲下來了。
比如:19 01 08這個命令的用途,就是讀取所有狀態為confirm的DTC的數量。
sub-function = 0x02 (reportDTCByStatusMask)
sub-function = 0x02用於讀取符合特定條件的DTC列表,此時parameter仍然為一個byte的Mask,用於與DTC的Status進行“與”運算,而ECU返回的則是"與"運算之后結果不為0的DTC列表。
比如19 02 01這個命令的用途,就是讀取所有狀態為active的DTC的數量。此時ECU返回的格式應該是59 02 01 XX XX XX 01 YY YY YY 09......。返回的DTC列表中的每個條目為4個字節,前三個字節用於標識DTC,比如 XX XX XX,最后一個字節用於標識DTC狀態,比如01,表示DTC是active的,09表示DTC是active且confirm的。
sub-function = 0x06 (reportDTCExtDataRecordByDTCNumber)
sub-function = 0x06用於讀取某個DTC及其相關的環境數據,此時parameter為4個byte,前三個byte用於標識我們要讀取的DTC,第四個byte用於標識要讀取的環境數據的范圍,UDS規定使用FF來表示讀取所有的環境數據,各廠家可以要根據自己的需求定義其他的值來代表要讀取的環境數據的范圍。環境數據包括DTC狀態,優先級,發生次數,老化計數器,時間戳,里程等,廠家還可以根據自己的需求定義一些此DTC產生時的測量數據。
比如 19 06 XX XX XX FF就表示讀取 XX XX XX這個DTC的所有環境數據,ECU的返回值應該是59 06 XX XX XX AA BB CC DD.....,其中AA BB CC DD...代表的就是XX XX XX這個DTC產生時所一起存儲的環境數據。
sub-function = 0x0E(reportMostRecentConfirmedDTC)
sub-function = 0x0E時,不需要parameter。0x0E表示,要求ECU上報最近的一條被置為confirm的DTC。我在《統一診斷服務 (Unified diagnostic services , UDS) (三)》一文中介紹過0x86服務,sub-function = 0x0E的19服務通常被作為參數傳遞給86指令,要求ECU在發生DTC存儲的時候進行自動上報,即19 0E這兩個字節的指令被嵌入到86服務的命令中。這條命令在開發階段會用到,比如驗證某個故障路徑是否生效。
這篇文章將介紹InputOutputControlByIdentifier (0x2F) 和RoutineControl (0x31) 這兩個診斷服務的用途和用法。它倆的作用有點類似,都是調用ECU內部一些預定義的操作序列,相當於是我們從外部利用診斷手段控制ECU的接口。
InputOutputControlByIdentifier (0x2F)
ECU簡單來說就是一個對輸入(sensor)進行計算再產生輸出(actuator)的系統。2F這個服務就是對ECU的輸入和輸出進行控制。這個服務在生產線上會需要使用,比如,在總裝階段,工人需要驗證車上的各種功能是否正常,例如四個車窗的升降是否正常,如果挨個開關去按,那效率很低,如果通過一個診斷命令就能夠觀察到車窗升降的情況,效率則高得多。
ECU就是一個處理輸入信息、輸出控制的系統
比如,ECU接收一個輸入信號A,我們就可以利用2F給這個A賦個我們需要的值;ECU對某個執行器B進行控制,我們就可以利用2F服務再配上某些特定的參數來實現對B的控制,例如門控對車窗升降、后視鏡折疊等的控制。
2F命令的格式
2F服務的request由4部分組成
- SID
- dataIdentifier,用於標識被控制的IO對象
- controlOptionRecord,用於標識控制方式,比如是啟動、停止控制,還可以有一些自定義的參數來進行更精准的控制,比如讓某個執行器的動作持續多長時間。controlOptionRecord又分為兩部分,分別是1個byte的inputOutputControlParameter,以及若干byte由廠家自定義使用的controlState。
- controlEnableMaskRecord,這是一個可選參數,用於標識controlOptionRecord中的哪些parameter被使用。
UDS明確定義了四種inputOutputControlParameter
0x00 returnControlToECU (將控制權還給ECU,即結束控制)
0x01 resetToDefault (將dataIdentifier所引用的輸入信號、內部參數、輸出信號等設為默認值)
0x02 freezeCurrentState(將dataIdentifier所引用的輸入信號、內部參數、輸出信號等凍結住)
0x03 shortTermAdjustment (將dataIdentifier所引用的輸入信號、內部參數、輸出信號進行設置,其實就相當於開始了對ECU的控制)
另外,UDS定義可以用22服務讀取2F服務中使用的dataIdentifier,返回值是狀態信息,具體的狀態信息是什么,則由使用者自定義了。
我們以14229中舉的一個例子來感受一下2F服務:
這個例子是使用2F控制Air Inlet Door Position (進氣口門位置),用標識符0x9B00來標識進氣口門的位置。Air Inlet Door Position [%] = decimal(Hex) * 1 [%] ,即用一個百分比來表示這個位置。
step1:
tester 發送22 9B 00讀取當前進氣口門的位置
ECU返回62 9B 00 0A , 0x0A = 10(dec),表示當前位置是10%
step2:
tester 發送2F 9B 00 03 3C ,表示要將進氣口門的位置調整到60%,0x3C = 60(dec)
ECU返回6F 9B 00 03 0C,表示接受控制,當前進氣口門的位置為12%。因為ECU收到請求后是立刻響應的,而門的位置調節需要時間,所以還沒有達到60%。
step3:
過一段時間后tester 發送22 9B 00讀取當前進氣口門的位置
ECU返回62 9B 00 3C , 0x3C = 60(dec),表示當前位置已經到了60%
step4:
tester 發送2F 9B 00 00,將控制權交還給ECU
ECU返回6F 9B 00 00 3A,表示接受請求,當前位置為58%
step5:
tester 發送2F 9B 00 02,凍結9B 00這個ID所代表的進氣口門位置這個狀態
ECU返回6F 9B 00 02 32,表示接受請求,當前位置保持在50%
RoutineControl (0x31)
31服務是調用ECU內置的一些操作序列的接口,這個服務的應用很靈活,因為廠家可以根據自己的需要為ECU定義各種各樣的內部操作,而要執行這些操作只需要調用31服務就好了。典型的用途包括檢查邊界條件、清除閃存、對數據進行較驗、對軟硬件依賴性進行校驗等,甚至有需要的話可以進行恢復出廠設置的操作,還有很多與ECU自身邏輯功能相關的操作也可以定義。
31命令的格式2F命令的格式
31服務的request由4部分組成
- SID
- sub-function,用於標識要執行什么動作,啟動(0x01)、停止(0x02)、查詢結果(0x03)
- routineIdentifier,用於標識要執行的routine
- routineControlOptionRecord,這是一個可選參數,用於標識routine執行時所需要的參數,由各家自定義它的內容
舉個例子,假設用0x0809這個ID來代表檢查ECU是否滿足軟件刷寫條件(比如車速、轉速為0,KL15接通等)的routine。
tester發送31 01 08 09來啟動0x0809這個routine
如果所有條件都滿足,則ECU返回71 01 08 09作為echo即可,如果條件不滿足,則ECU返回71 01 08 09 XX YY ZZ,后邊的XX YY ZZ則表明哪些條件不滿足,具體的內容就由廠家自己定義了。
在關於UDS的第二篇文章中,我提到過UDS定義的服務從邏輯上分為6類,在第二至第六篇中已經講解了前五類,在本文中將介紹最后一類UDS服務,即Upload Download functional unit ,數據的上傳下載。
從成本等角度考慮,汽車ECU中用於緩存診斷服務數據的buffer大小有限,所以當我們需要讀取或寫入超過buffer大小的數據時,就無法簡單地使用2E和22服務了,UDS據此定義了幾個將大塊數據寫入或讀出的服務,即數據下載和上傳。
Upload Download functional unit總共定義了5個診斷服務,分別是:
- RequestDownload (0x34):客戶端向服務器請求下載數據
- RequestUpload (0x35)客戶端向服務器請求上傳數據
- TransferData(0x36) 客戶端向服務器傳數據(下載),或者服務器向客戶端傳數據(上傳)
- RequestTransferExit(0x37)數據傳輸完成,請求退出
- RequestFileTransfer(0x38) 傳輸文件的操作,可以用於替代上傳下載的服務。
下圖是數據下載的簡略過程,用到了34,36,37這三個服務,如果是上傳的話,34服務被35服務替換,數據傳輸方向變一下,就可以了。
Tester向ECU刷寫數據的大概過程
RequestDownload (0x34)
0x34服務用於啟動下載傳輸,作用是告知ECU准備接受數據,ECU則通過0x74 response告訴診斷儀自己是否允許傳輸,以及自己的接受能力是多大。
0x34服務的請求格式
0x34服務的請求格式包括5個部分
第一部分:1個byte的SID
第二部分:1個byte的dataFormatIdentifier,這里面標識了數據格式相關的信息,比如數據是否有壓縮,是否有加密,用的什么算法加密等,應該由主機廠與供應商約定好,用哪個bit來表示壓縮、加密等信息。
第三部分:1個字節的addressAndLengthFormatIdentifier,用於指示后面兩個部分所占用的字節,高4bit表示memorySize所占的字節長度,低4bit表示memoryAddress
所占的字節長度。在這個例子中我將這兩個值分別設置為n和m。
第四部分:m個字節的memoryAddress,由addressAndLengthFormatIdentifier中的低4bit指示。含義是要寫入數據在ECU中的邏輯地址。
第五部分:n個字節的memorySize,由addressAndLengthFormatIdentifier中的高4bit指示。含義是要寫入數據的字節數。
ECU收到請求之后,如果允許傳輸的話,會給出如下response
0x34服務的響應格式
第一部分:1個byte的 Response SID
第二部分:1個byte的dataFormatIdentifier作為echo
第三部分:maxNumberOfBlockLength,長度不定,表示可以通過0x36服務一次傳輸的最大數據量。
TransferData(0x36):
如果34服務得到了正確響應,tester就要啟動數據傳輸過程了,使用的就是36服務。36服務的格式如下。
0x36服務的請求格式
第一部分:1個byte的 SID
第二部分:1個byte的blockSequenceCounter,標識當前傳輸的是第幾個數據塊,或者簡單地說就是第幾次調用36服務。
第三部分:transferRequestParameterRecord,傳輸的數據。第次傳輸數據量的上限就是34服務響應中的maxNumberOfBlockLength。
舉例:如果ECU告知tester,maxNumberOfBlockLength = 20,也就是說tester每次通過36服務只能發送最多20個字節,其中還包括了SID和blockSequenceCounter,所以實際上每次可傳的數據信息只有18個字節。如果tester要傳的數據為50個字節,則需要傳輸三次,每次分別傳輸18,18,14個字節,即調用3次36服務。
36的響應很簡單,就是一個字節的Response SID再加一個字節的blockSequenceCounter作為echo。
RequestTransferExit(0x37):
37服務用於退出上傳下載,如果之前的34和36服務都順利執行完成,那么37服務就可以得到ECU的positive response。
格式很簡單,請求就是37,正確響應就是77,都是一個字節。
如果前面的36服務沒有執行完成,以我前面舉的例子來說,比如這個數據塊有50個字節,但是tester只發了兩次36服務傳了36個字節,那么這次傳輸對於ECU來說是失敗的,所以ECU應該給出NRC 0x7F 37 24,表示診斷序列執行有錯誤。
關於UDS所定義的診斷服務到這里就寫完了。接下來我會寫兩篇文章補充一下UDS系列,分別介紹一下DTC的8個狀態位的邏輯關系以及向ECU刷寫數據或軟件的完整流程。在此之后我會寫幾篇文章來講述UDS在CAN總線上的實現,即所謂的UDSonCAN,涉及到TP層的分包、流控制、錯誤識別等內容,還有基於CAN實現的UDS中涉及到的各種時間參數。感興趣的話可以繼續關注。