IUdsClient Interface¶
A single Unified Diagnostic Services (ISO 14229-1) client bound to one IIsoTpChannel. One client = one tester ↔ ECU relationship; overlapping requests from multiple callers are serialized by the client so at most one UDS request is outstanding at any time (mirrors ISO 14229-1 §7.3's "one active request per tester" model).
Implements IDisposable
Remarks¶
The surface covers eleven services: the seven of SRS FR-UDS-001..007 (0x10, 0x11, 0x22, 0x27, 0x2E, 0x31, 0x3E) and the four of the upload/download sequence, FR-UDS-012 (0x34, 0x35, 0x36, 0x37), with a multi-DID 0x22 (FR-UDS-011) and the one-shot DownloadAsync(byte, byte, ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, CancellationToken) and UploadAsync(byte, byte, ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, CancellationToken) on top -- plus the raw escape hatch SendRawAsync(ReadOnlyMemory<byte>, CancellationToken). Every method: - Serializes on the client's internal request lock — callers may invoke from arbitrary threads. - Applies P2/P2* timing (SRS FR-UDS-008/009): the initial response is awaited for at most P2ClientMax; every NRC 0x78 (requestCorrectlyReceived-ResponsePending) restarts the P2* (P2StarClientMax) timer. - Surfaces negative responses as UdsNegativeResponseException with the request SID and the raw NRC byte (SRS FR-UDS-010).
The client honours the caller's CancellationToken for both the serialization gate and the response wait; a cancelled call abandons the response but does not corrupt the client (the next call will still see a clean state).
IDisposable.Dispose is thread-safe and idempotent; disposing an active client cancels any pending request and stops the TesterPresent keep-alive (if any). It then waits for the keep-alive loop to end and for the request in flight to release the request lock, each wait bounded by five seconds -- up to ten in all where both outlast the cancellation -- and holds the calling thread meanwhile. DisposeAsync(this IUdsClient) does the same without holding a thread.
Properties¶
IUdsClient.Channel Property¶
The channel this client is bound to (never null).
Property Value¶
IUdsClient.CurrentSession Property¶
The most recently negotiated session, updated on a successful DiagnosticSessionControlAsync(byte, CancellationToken) and reset to Default after a successful EcuResetAsync(UdsEcuResetType, CancellationToken). Starts at Default because ISO 14229-1 §9.2 guarantees an ECU starts up in the default session.
Property Value¶
Remarks¶
Only those two methods move it. A DiagnosticSessionControl or ECUReset sent through
SendRawAsync(ReadOnlyMemory<byte>, CancellationToken) -- answered, or suppressed (10 83, 11 81), which
the ECU acts on without a word -- changes the ECU's session and leaves this property, and
the P2/P2* budgets the session's record would have set, as they were (#354).
IUdsClient.Options Property¶
The immutable options used at construction.
Property Value¶
Methods¶
IUdsClient.DiagnosticSessionControlAsync(byte, CancellationToken) Method¶
Sends DiagnosticSessionControl (0x10) with a raw sub-function byte. Convenience for vendor-specific session numbers that are not covered by UdsSessionType. The returned session parameter record sets the client's P2/P2* budgets as described on DiagnosticSessionControlAsync(UdsSessionType, CancellationToken).
System.Threading.Tasks.Task<byte[]> DiagnosticSessionControlAsync(byte sessionType, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
sessionType Byte
cancellationToken CancellationToken
Returns¶
Exceptions¶
ArgumentOutOfRangeException
sessionType is 0x00 (ISOSAEReserved) or has bit 7 set: that bit is
suppressPosRspMsgIndication, not part of the session type, and this method waits for the
response (#57).
IUdsClient.DiagnosticSessionControlAsync(UdsSessionType, CancellationToken) Method¶
Sends DiagnosticSessionControl (0x10, SRS FR-UDS-001) with a named UdsSessionType. Returns the raw parameter bytes echoed back by the ECU (session parameter record, typically 4 bytes carrying P2/P2* server timing).
System.Threading.Tasks.Task<byte[]> DiagnosticSessionControlAsync(CanKit.Pro.Uds.UdsSessionType session, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
session UdsSessionType
cancellationToken CancellationToken
Returns¶
Remarks¶
The record's P2Server_max (bytes 0..1, 1 ms units) and P2*Server_max (bytes 2..3, 10 ms units) set the client's budgets for every later request: P2 becomes the longer of P2ClientMax and P2Server_max + SessionTimingMargin, P2* the longer of P2StarClientMax and P2*Server_max + SessionTimingMargin. A configured budget is never shortened. Each successful response starts again from the configured budgets, so a record shorter than 4 bytes leaves them as configured; a successful EcuResetAsync(UdsEcuResetType, CancellationToken) returns to them as well (#340). Options keeps reporting the configured values.
IUdsClient.DownloadAsync(byte, byte, ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, CancellationToken) Method¶
Convenience one-shot download that runs the full 0x34 → N × 0x36 → 0x37 sequence for
data. The client negotiates maxNumberOfBlockLength with
RequestDownload, then loops TransferDataAsync(byte, ReadOnlyMemory<byte>, CancellationToken) with an automatically-managed
block sequence counter (starts at 0x01, increments per block, wraps
0xFF → 0x00), and finally calls RequestTransferExitAsync(ReadOnlyMemory<byte>, CancellationToken).
When dataFormatIdentifier is 0x00 (no compression / no
encryption), memorySize is the big-endian byte count sent in
RequestDownload and must equal the length of data; a mismatch is
rejected before RequestDownload. When compression or encryption is selected,
memorySize is the decoded target memory range and
data is the encoded payload this client forwards unchanged, so
their lengths are not compared.
System.Threading.Tasks.Task DownloadAsync(byte dataFormatIdentifier, byte addressAndLengthFormatIdentifier, System.ReadOnlyMemory<byte> memoryAddress, System.ReadOnlyMemory<byte> memorySize, System.ReadOnlyMemory<byte> data, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
dataFormatIdentifier Byte
addressAndLengthFormatIdentifier Byte
memoryAddress ReadOnlyMemory<Byte>
memorySize ReadOnlyMemory<Byte>
data ReadOnlyMemory<Byte>
cancellationToken CancellationToken
Returns¶
Exceptions¶
ArgumentException
dataFormatIdentifier is
0x00 and memorySize does not decode to the length of
data.
ArgumentOutOfRangeException
dataFormatIdentifier
is 0x00 and memorySize has nonzero high-order bytes beyond
what a UInt64 can represent.
UdsProtocolException
The ECU reported a
maxNumberOfBlockLength of 0 or 1 so no payload byte would fit in a
TransferData request, or a chunk validation failed.
Remarks¶
No block is retried. Beyond the repeat after NRC 0x21 (busyRepeatRequest) that every request gets (MaxBusyRepeatRequests), the first failure of a TransferData -- a negative response such as NRC 0x73 (wrongBlockSequenceCounter), a timeout, a transport error -- ends the call with that exception, and no RequestTransferExit follows, so the server's download is left where the failed block left it. This is a scope limit of this convenience method, not a reading of ISO 14229-1: whether and how the standard has a client repeat a block has not been checked against the text (#354). A caller that wants to repeat blocks drives RequestDownloadAsync(byte, byte, ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, CancellationToken), TransferDataAsync(byte, ReadOnlyMemory<byte>, CancellationToken) and RequestTransferExitAsync(ReadOnlyMemory<byte>, CancellationToken) itself.
IUdsClient.EcuResetAsync(UdsEcuResetType, CancellationToken) Method¶
Sends ECUReset (0x11, SRS FR-UDS-005) and returns the raw powerDownTime parameter (0..1 bytes) echoed back by the ECU. On success, CurrentSession is reset to Default to match the ECU returning to the default session, and the P2/P2* budgets to the configured P2ClientMax / P2StarClientMax. Callers should typically wait for the ECU to reboot before issuing further requests.
System.Threading.Tasks.Task<byte[]> EcuResetAsync(CanKit.Pro.Uds.UdsEcuResetType resetType, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
resetType UdsEcuResetType
cancellationToken CancellationToken
Returns¶
IUdsClient.ReadDataByIdentifierAsync(IReadOnlyList<ushort>, IReadOnlyDictionary<ushort,int>, CancellationToken) Method¶
Sends ReadDataByIdentifier (0x22) with more than one DID in a single request (SRS FR-UDS-011, ISO 14229-1 §9.3.4). Returns a dictionary keyed by DID with the raw data-record bytes of each identifier the ECU answered. An ECU that supports only some of the requested DIDs answers with those (ISO 14229-1 §10.2), so a requested DID that has no key in the result was not answered; if none is supported the ECU's negative response (requestOutOfRange) is raised instead.
System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyDictionary<ushort,byte[]>> ReadDataByIdentifierAsync(System.Collections.Generic.IReadOnlyList<ushort> dataIdentifiers, System.Collections.Generic.IReadOnlyDictionary<ushort,int> dataRecordLengths, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
dataIdentifiers IReadOnlyList<UInt16>
DIDs to request, in the order they are placed on the wire.
dataRecordLengths IReadOnlyDictionary<UInt16,Int32>
Expected dataRecord length (bytes) for every requested DID. ISO 14229-1 §9.3.4.4
does not encode lengths in the positive response — the client must know them from the
ECU's DID definition (ODX/CDD/etc.). Zero-length records are allowed.
cancellationToken CancellationToken
Cancels the wait for the ECU response.
Returns¶
Task<IReadOnlyDictionary<UInt16,Byte[]>>
Exceptions¶
ArgumentException
A requested DID has no length entry, or a length is
negative.
UdsProtocolException
The ECU response is malformed, truncated, carries no
data record at all, repeats a DID, or contains a DID that was not requested behind its
first. A positive response whose <em>first</em> DID was not requested is not this
request's answer but a stray -- the receive loop discards it and the wait goes on (#340).
A DID that is merely not answered is not an error: it is absent from the result.
IUdsClient.ReadDataByIdentifierAsync(ushort, CancellationToken) Method¶
Sends ReadDataByIdentifier (0x22, SRS FR-UDS-002) for a single Data Identifier. Returns the raw data-record bytes that followed the DID in the positive response.
System.Threading.Tasks.Task<byte[]> ReadDataByIdentifierAsync(ushort dataIdentifier, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
dataIdentifier UInt16
cancellationToken CancellationToken
Returns¶
IUdsClient.RequestDownloadAsync(byte, byte, ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, CancellationToken) Method¶
Sends RequestDownload (0x34, ISO 14229-1 §14.2, SRS FR-UDS-012). Negotiates a download session with the ECU: the tester declares the payload format (compression / encryption via dataFormatIdentifier) and the target memory range (memoryAddress, memorySize) whose widths are packed in addressAndLengthFormatIdentifier. The ECU replies with the maximum TransferData block length it will accept, wrapped in UdsDownloadResponse.
System.Threading.Tasks.Task<CanKit.Pro.Uds.UdsDownloadResponse> RequestDownloadAsync(byte dataFormatIdentifier, byte addressAndLengthFormatIdentifier, System.ReadOnlyMemory<byte> memoryAddress, System.ReadOnlyMemory<byte> memorySize, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
dataFormatIdentifier Byte
Byte encoding the compression method (high nibble)
and encryption method (low nibble); 0x00 means "no compression / no
encryption".
addressAndLengthFormatIdentifier Byte
Byte packing the width of
memoryAddress (low nibble) and memorySize
(high nibble) in bytes. Both widths MUST be in 1..0x0F and MUST match the
respective buffer lengths.
memoryAddress ReadOnlyMemory<Byte>
Big-endian target start address.
memorySize ReadOnlyMemory<Byte>
Big-endian target byte count.
cancellationToken CancellationToken
Cancels the wait for the ECU response.
Returns¶
Exceptions¶
ArgumentOutOfRangeException
A width nibble in
addressAndLengthFormatIdentifier is zero, or does not match the
buffer length.
IUdsClient.RequestTransferExitAsync(ReadOnlyMemory<byte>, CancellationToken) Method¶
Sends RequestTransferExit (0x37, ISO 14229-1 §14.4, SRS FR-UDS-012) to close the current transfer session. transferRequestParameterRecord is an optional vendor-specific record (e.g. checksum) appended after the SID.
System.Threading.Tasks.Task RequestTransferExitAsync(System.ReadOnlyMemory<byte> transferRequestParameterRecord=default(System.ReadOnlyMemory<byte>), System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
transferRequestParameterRecord ReadOnlyMemory<Byte>
cancellationToken CancellationToken
Returns¶
IUdsClient.RequestUploadAsync(byte, byte, ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, CancellationToken) Method¶
Sends RequestUpload (0x35, ISO 14229-1 §14.1, SRS FR-UDS-012). Mirror of RequestDownloadAsync(byte, byte, ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, CancellationToken) for the tester-reads-from-ECU direction; the returned MaxNumberOfBlockLength constrains the size of TransferData responses the ECU will emit.
System.Threading.Tasks.Task<CanKit.Pro.Uds.UdsUploadResponse> RequestUploadAsync(byte dataFormatIdentifier, byte addressAndLengthFormatIdentifier, System.ReadOnlyMemory<byte> memoryAddress, System.ReadOnlyMemory<byte> memorySize, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
dataFormatIdentifier Byte
addressAndLengthFormatIdentifier Byte
memoryAddress ReadOnlyMemory<Byte>
memorySize ReadOnlyMemory<Byte>
cancellationToken CancellationToken
Returns¶
IUdsClient.RoutineControlAsync(UdsRoutineControlType, ushort, ReadOnlyMemory<byte>, CancellationToken) Method¶
Sends RoutineControl (0x31, SRS FR-UDS-004). The routine control option record (routineControlOptionRecord) is sent verbatim after the routine identifier; the returned array contains the routine info bytes from the positive response (excluding the echoed sub-function and routine identifier).
System.Threading.Tasks.Task<byte[]> RoutineControlAsync(CanKit.Pro.Uds.UdsRoutineControlType routineType, ushort routineIdentifier, System.ReadOnlyMemory<byte> routineControlOptionRecord=default(System.ReadOnlyMemory<byte>), System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
routineType UdsRoutineControlType
routineIdentifier UInt16
routineControlOptionRecord ReadOnlyMemory<Byte>
cancellationToken CancellationToken
Returns¶
IUdsClient.SecurityAccessAsync(byte, Func<byte[],byte[]>, CancellationToken) Method¶
Runs the ISO 14229-1 §9.4 SecurityAccess (0x27, SRS FR-UDS-006) two-step exchange:
1. Send 0x27 requestSeedLevel, receive the seed bytes.
2. Invoke computeKey synchronously with the seed and
the returned key, then send 0x27 sendKeyLevel with the caller-computed key
bytes.
requestSeedLevel must be an odd byte in 0x01..0x7D and
sendKeyLevel = requestSeedLevel + 1 is derived automatically, so at most
0x7E. A seed of all zeroes -- of any length, including none -- means "already
unlocked" (ISO 14229-1 §9.4.5.3) and short-circuits the exchange without invoking
computeKey or sending a key.
System.Threading.Tasks.Task SecurityAccessAsync(byte requestSeedLevel, System.Func<byte[],byte[]> computeKey, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
requestSeedLevel Byte
computeKey Func<Byte[],Byte[]>
cancellationToken CancellationToken
Returns¶
Exceptions¶
ArgumentOutOfRangeException
requestSeedLevel is not
an odd byte in the range 0x01..0x7D.
ArgumentNullException
computeKey is null.
Remarks¶
The client's request lock is held from the seed request to the key's answer, and so across computeKey: no other request -- the StartTesterPresentKeepAlive(Nullable<TimeSpan>) TesterPresent included -- goes out in between, so nothing can come between seed and key on the ECU's side. The cost is that a computeKey that takes longer than the server's S3 timer (an HSM-backed one, say) also holds back the keep-alive, and the session may time out before the key is sent. Whether ISO 14229-1 lets a TesterPresent between seed and key leave the seed valid -- in which case the keep-alive alone could be let through during computeKey -- has not been checked against the text; until it is, the lock stays (#354).
IUdsClient.SendRawAsync(ReadOnlyMemory<byte>, CancellationToken) Method¶
Sends the raw request bytes verbatim (starting with the SID) and returns the ECU's raw positive-response bytes (again including the response SID). The same P2/P2* timing and NRC handling apply as for the strongly-typed methods. A request whose sub-function byte has suppressPosRspMsgIndication set (bit 7, on a service that carries a sub-function) is sent without waiting: an empty array comes back once the frame is confirmed, and a negative response the server may still send is not waited for (#57).
System.Threading.Tasks.Task<byte[]> SendRawAsync(System.ReadOnlyMemory<byte> request, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
request ReadOnlyMemory<Byte>
cancellationToken CancellationToken
Returns¶
Remarks¶
The request is not interpreted: a session change or reset sent here does not move CurrentSession or the P2/P2* budgets, whether it is answered or suppressed (#354). Use DiagnosticSessionControlAsync(byte, CancellationToken) and EcuResetAsync(UdsEcuResetType, CancellationToken) where the client should follow the session.
IUdsClient.StartTesterPresentKeepAlive(Nullable<TimeSpan>) Method¶
Starts a background TesterPresent (0x3E) keep-alive that fires every period (defaults to TesterPresentPeriod) until the returned IDisposable is disposed or the client itself is disposed. The keep-alive uses TesterPresentAsync(bool, CancellationToken) under the hood so it serializes with normal requests through the same request lock; a slow request never causes a stale keep-alive frame to interleave (SRS FR-UDS-007).
Parameters¶
Override for the send interval; must be positive.
Returns¶
Exceptions¶
InvalidOperationException
A keep-alive is already running; call
IDisposable.Dispose on the previous handle first.
Remarks¶
A TesterPresent that fails -- a timeout, a negative response, a transport error -- is
dropped and the next one goes out a period later; nothing reports it, and the channel's
BackgroundExceptionOccurred does not carry it either. A session the ECU has left
(after a reset, or with S3 run out) therefore shows only in the answer to the next
request, typically NRC 0x7E or 0x7F. The keep-alive ends without notice when the client
or its channel is disposed.
IUdsClient.TesterPresentAsync(bool, CancellationToken) Method¶
Sends a single TesterPresent (0x3E, SRS FR-UDS-007). When
suppressPositiveResponse is true the ISO 14229-1 §7.5
suppressPositiveResponse bit is set (sub-function 0x80) and the method returns as
soon as the request is on the wire — the ECU is expected to stay silent. Otherwise the
method awaits the positive response.
System.Threading.Tasks.Task TesterPresentAsync(bool suppressPositiveResponse=true, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
suppressPositiveResponse Boolean
cancellationToken CancellationToken
Returns¶
IUdsClient.TransferDataAsync(byte, ReadOnlyMemory<byte>, CancellationToken) Method¶
Sends TransferData (0x36, ISO 14229-1 §14.3, SRS FR-UDS-012) with the caller-supplied
block sequence counter and payload chunk. Returns the ECU's transferResponseParameterRecord
(the bytes that follow the echoed block sequence counter in the positive response — may
be empty). The client validates that the ECU echoes back the exact
blockSequenceCounter.
System.Threading.Tasks.Task<byte[]> TransferDataAsync(byte blockSequenceCounter, System.ReadOnlyMemory<byte> data, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
blockSequenceCounter Byte
Per ISO 14229-1 §14.3.2 the counter starts at
0x01 for the first TransferData following RequestDownload/Upload, is incremented
on each successful transfer, and wraps from 0xFF back to 0x00.
data ReadOnlyMemory<Byte>
Payload chunk. Total request size (SID + BSC + payload = 2 + data.Length) MUST
NOT exceed the ECU's MaxNumberOfBlockLength. May be
empty when the ECU is expected to synthesise data (e.g. the upload direction).
cancellationToken CancellationToken
Cancels the wait for the ECU response.
Returns¶
IUdsClient.UploadAsync(byte, byte, ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, CancellationToken) Method¶
Convenience one-shot upload that runs the full 0x35 → N × 0x36 → 0x37 sequence and
returns the bytes read from the ECU. The client negotiates with RequestUpload, then
loops TransferDataAsync(byte, ReadOnlyMemory<byte>, CancellationToken) with an automatically-managed block sequence
counter (starts at 0x01, increments per block, wraps 0xFF → 0x00),
concatenating the ECU's transferResponseParameterRecords until
memorySize bytes were read, and finally calls
RequestTransferExitAsync(ReadOnlyMemory<byte>, CancellationToken).
System.Threading.Tasks.Task<byte[]> UploadAsync(byte dataFormatIdentifier, byte addressAndLengthFormatIdentifier, System.ReadOnlyMemory<byte> memoryAddress, System.ReadOnlyMemory<byte> memorySize, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
dataFormatIdentifier Byte
addressAndLengthFormatIdentifier Byte
memoryAddress ReadOnlyMemory<Byte>
memorySize ReadOnlyMemory<Byte>
cancellationToken CancellationToken
Returns¶
Exceptions¶
ArgumentOutOfRangeException
memorySize has nonzero
high-order bytes beyond what a UInt64 can represent; nothing is sent.
UdsProtocolException
The ECU delivered an empty TransferData payload
before the declared size was reached, or memorySize exceeds what can
reasonably be buffered.
IUdsClient.WriteDataByIdentifierAsync(ushort, ReadOnlyMemory<byte>, CancellationToken) Method¶
Sends WriteDataByIdentifier (0x2E, SRS FR-UDS-003). Completes successfully when the ECU echoes the DID; the DID echo is validated against the request.
System.Threading.Tasks.Task WriteDataByIdentifierAsync(ushort dataIdentifier, System.ReadOnlyMemory<byte> data, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
dataIdentifier UInt16
data ReadOnlyMemory<Byte>
cancellationToken CancellationToken