uds:   ISO 14229 (Unified Diagnostic Services) in pure Racket
1 Quick start
2 Service identifiers
positive-sid
response-sid->request-sid
make-sub-function-byte
parse-sub-function-byte
3 Negative response codes
negative-response
4 Diagnostic trouble codes
dtc
dtc-status
5 Requests
request
make-request
diagnostic-session-control
ecu-reset
tester-present
control-dtc-setting
clear-diagnostic-information
read-dtc-by-status-mask
report-number-of-dtc-by-status-mask
report-supported-dtc
security-access-request-seed
security-access-send-key
read-data-by-identifier
write-data-by-identifier
input-output-control-by-identifier
routine-control
read-memory-by-address
write-memory-by-address
request-download
transfer-data
request-transfer-exit
6 Responses
response-parse
positive-response
7 Caveats
9.3

uds: ISO 14229 (Unified Diagnostic Services) in pure Racket🔗ℹ

 (require uds) package: uds

This package implements the message layer of ISO 14229-1 — UDS (Unified Diagnostic Services), the application protocol spoken by automotive ECUs over ISO-TP (isotp) or DoIP. It covers service identifiers, negative response codes, diagnostic trouble codes, and request/response construction and parsing.

The library is transport-agnostic and pure: builders return the payload bytes of one ISO-TP message and parsers consume them; timing, transport and security-algorithm concerns stay with the caller. There is no FFI and no system dependency.

1 Quick start🔗ℹ

(require uds)
 
 
(diagnostic-session-control 'extended)
 
 
(read-data-by-identifier '(61840))
 
 
(response-parse #"P\3\0002\0\310")
(session-control-response (positive-response-data (response-parse #"P\3\0002\0\310")))

2 Service identifiers🔗ℹ

The sid:* bindings name every ISO 14229-1 service (sid:diagnostic-session-control, sid:read-data-by-identifier, …). service-name maps an ID back to a symbol, and service-uses-sub-function? tells whether the service’s second byte is a sub-function — the distinction that drives generic framing.

procedure

(positive-sid sid) → (integer-in 0 255)

  sid : (integer-in 0 255)
The positive-response marker: sid | 64.

procedure

(response-sid->request-sid sid) → (integer-in 0 255)

  sid : (integer-in 0 255)
Inverse of positive-sid (clears the marker bit).

procedure

(make-sub-function-byte sub suppress?) → (integer-in 0 255)

  sub : (integer-in 0 127)
  suppress? : boolean?

procedure

(parse-sub-function-byte b) → 
(integer-in 0 127) boolean?
  b : (integer-in 0 255)
Encode/decode the sub-function byte: bits 0–6 carry the sub-function, bit 7 is suppressPosRspMsgIndicationBit.

3 Negative response codes🔗ℹ

Negative responses are framed as 7F <echoed SID> <NRC>.

struct

(struct negative-response (sid nrc))

  sid : (integer-in 0 255)
  nrc : (integer-in 0 255)
The parsed negative response. negative-response-parse and negative-response-bytes convert to and from wire bytes; nrc-name maps a code to a symbol (nrc:request-out-of-range, nrc:security-access-denied, …); response-pending? recognizes the requestCorrectlyReceived-ResponsePending code (0x78) that tells the tester to keep waiting.

4 Diagnostic trouble codes🔗ℹ

struct

(struct dtc (number status-byte))

  number : (integer-in 0 65535)
  status-byte : (integer-in 0 255)
One trouble code: a 16-bit number and a status byte. The number’s text form ("P0123") maps through dtc-text->number / dtc-number->text: bits 15–14 encode the system letter (P/C/B/U), bits 13–12 the first digit, and the remaining three digits occupy one BCD nibble each. parse-dtc-records reads the 3-byte record runs of ReadDTCInformation responses.

struct

(struct dtc-status (test-failed
    test-failed-this-operation-cycle
    pending
    confirmed
    test-not-completed-since-last-clear
    test-failed-since-last-clear
    test-not-completed-this-operation-cycle
    warning-indicator-requested))
  test-failed : boolean?
  test-failed-this-operation-cycle : boolean?
  pending : boolean?
  confirmed : boolean?
  test-not-completed-since-last-clear : boolean?
  test-failed-since-last-clear : boolean?
  test-not-completed-this-operation-cycle : boolean?
  warning-indicator-requested : boolean?
The status byte (ISO 14229-1 Annex D) as flags; make-dtc-status, dtc-status->byte and byte->dtc-status convert. +dtc-group-all+ (0xFFFFFF) is the "all DTCs" group for ClearDiagnosticInformation.

5 Requests🔗ℹ

struct

(struct request (sid sub-function suppress? data))

  sid : (integer-in 0 255)
  sub-function : (or/c #f (integer-in 0 127))
  suppress? : boolean?
  data : bytes?
A parsed request: request-parse decodes any payload, resolving the sub-function/suppress-bit split for sub-function services.

procedure

(make-request sid    
  [#:sub-function sub    
  #:suppress? suppress?    
  #:data data]) → bytes?
  sid : (integer-in 0 255)
  sub : (or/c #f (integer-in 0 127)) = #f
  suppress? : boolean? = #f
  data : bytes? = #""
Generic request framing; raises when the service does not use sub-functions but one (or the suppress bit) is requested. The typed builders below are preferred.

procedure

(diagnostic-session-control type    
  [#:suppress? suppress?]) → bytes?
  type : (or/c 'default 'programming 'extended (integer-in 0 127))
  suppress? : boolean? = #f

procedure

(ecu-reset type [#:suppress? suppress?]) → bytes?

  type : (or/c 'hard 'key-off-on 'soft (integer-in 0 127))
  suppress? : boolean? = #f

procedure

(tester-present [#:suppress? suppress?]) → bytes?

  suppress? : boolean? = #f

procedure

(control-dtc-setting mode    
  [#:suppress? suppress?    
  #:data data]) → bytes?
  mode : (or/c 'on 'off (integer-in 0 127))
  suppress? : boolean? = #f
  data : bytes? = #""

procedure

(clear-diagnostic-information group) → bytes?

  group : (integer-in 0 16777215)
Typed builders for the session-management services.

procedure

(read-dtc-by-status-mask mask) → bytes?

  mask : (integer-in 0 255)

procedure

(report-number-of-dtc-by-status-mask mask) → bytes?

  mask : (integer-in 0 255)

procedure

(report-supported-dtc [#:suppress? suppress?]) → bytes?

  suppress? : boolean? = #f
ReadDTCInformation builders for the three most used sub-functions.

procedure

(security-access-request-seed level) → bytes?

  level : (integer-in 0 63)

procedure

(security-access-send-key level key) → bytes?

  level : (integer-in 0 63)
  key : bytes?
SecurityAccess framing. Levels pair up: odd levels request a seed, the following even level sends the key; the builders enforce the parity.

procedure

(read-data-by-identifier dids) → bytes?

  dids : (listof (integer-in 0 65535))

procedure

(write-data-by-identifier did data) → bytes?

  did : (integer-in 0 65535)
  data : bytes?

procedure

(input-output-control-by-identifier did    
  data) → bytes?
  did : (integer-in 0 65535)
  data : bytes?
Data-identifier services; DIDs are 16-bit big-endian.

procedure

(routine-control action    
  routine-id    
  [#:record record    
  #:suppress? suppress?]) → bytes?
  action : (or/c 'start 'stop 'request-results (integer-in 0 127))
  routine-id : (integer-in 0 65535)
  record : bytes? = #""
  suppress? : boolean? = #f

procedure

(read-memory-by-address address    
  address-bytes    
  size    
  size-bytes) → bytes?
  address : integer?
  address-bytes : (integer-in 1 15)
  size : integer?
  size-bytes : (integer-in 1 15)

procedure

(write-memory-by-address address    
  address-bytes    
  data) → bytes?
  address : integer?
  address-bytes : (integer-in 1 15)
  data : bytes?

procedure

(request-download data-format-id    
  address    
  address-bytes    
  size    
  size-bytes) → bytes?
  data-format-id : (integer-in 0 255)
  address : integer?
  address-bytes : (integer-in 1 15)
  size : integer?
  size-bytes : (integer-in 1 15)

procedure

(transfer-data counter [#:data data]) → bytes?

  counter : (integer-in 0 255)
  data : bytes? = #""

procedure

(request-transfer-exit [#:data data]) → bytes?

  data : bytes? = #""
Memory and transfer services. The addressAndLengthFormatIdentifier (high nibble: address byte count, low nibble: size byte count) is built by encode-address-and-length and read back by decode-address-and-length.

6 Responses🔗ℹ

procedure

(response-parse payload)

 → (or/c positive-response? negative-response?)
  payload : bytes?
Classifies one response payload: bytes starting with 7F become a negative-response; everything else must be a positive response (SID | 0x40) and is split into echoed sub-function (for sub-function services) and the response record.

struct

(struct positive-response (sid sub-function data))

  sid : (integer-in 0 255)
  sub-function : (or/c #f (integer-in 0 127))
  data : bytes?
A parsed positive response; sid is the request service ID.

Record decoders for the common positive responses:

  • session-control-response — session type, P2 (ms) and P2* (ms; wire value × 10).

  • security-seed-response — the seed bytes.

  • max-block-length-response — maxNumberOfBlockLength.

  • number-of-dtc-response — format identifier and DTC count.

  • dtc-list-response — the DTC records as dtc? values.

  • transfer-data-response — echoed block counter and record.

7 Caveats🔗ℹ

  • Authentication (SID 0x29) framing is included in the service table but no typed builder yet; use make-request.

  • Security algorithms (seed/key) are ECU-specific by design and stay with the caller.

  • The library does not manage sessions, timing (P2/P2*) or retransmission; pair it with isotp for the transport layer.