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.
The full service-identifier table, as exported constants:
value
sid:diagnostic-session-control : (integer-in 0 255)
value
sid:ecu-reset : (integer-in 0 255)
value
sid:clear-diagnostic-information : (integer-in 0 255)
value
sid:read-dtc-information : (integer-in 0 255)
value
sid:read-data-by-identifier : (integer-in 0 255)
value
sid:read-memory-by-address : (integer-in 0 255)
value
value
sid:security-access : (integer-in 0 255)
value
sid:authentication : (integer-in 0 255)
value
sid:communication-control : (integer-in 0 255)
value
value
value
sid:define-data-by-identifier : (integer-in 0 255)
value
sid:write-data-by-identifier : (integer-in 0 255)
value
value
sid:routine-control : (integer-in 0 255)
value
sid:request-download : (integer-in 0 255)
value
sid:request-upload : (integer-in 0 255)
value
sid:transfer-data : (integer-in 0 255)
value
sid:request-transfer-exit : (integer-in 0 255)
value
sid:request-file-transfer : (integer-in 0 255)
value
sid:write-memory-by-address : (integer-in 0 255)
value
sid:tester-present : (integer-in 0 255)
value
sid:access-timing-parameter : (integer-in 0 255)
value
sid:secured-data-transmission : (integer-in 0 255)
value
sid:control-dtc-setting : (integer-in 0 255)
value
sid:response-on-event : (integer-in 0 255)
value
sid:link-control : (integer-in 0 255)
procedure
(service-name sid) → (or/c symbol? #f)
sid : (integer-in 0 255)
procedure
(service-uses-sub-function? sid) → boolean?
sid : (integer-in 0 255)
procedure
(positive-sid sid) → (integer-in 0 255)
sid : (integer-in 0 255)
procedure
(response-sid->request-sid sid) → (integer-in 0 255)
sid : (integer-in 0 255)
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)
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)
procedure
(negative-response-parse payload) → negative-response?
payload : bytes?
procedure
(negative-response-bytes sid nrc) → bytes?
sid : (integer-in 0 255) nrc : (integer-in 0 255)
procedure
nrc : (integer-in 0 255)
procedure
(response-pending? payload) → boolean?
payload : bytes?
The exported NRC constants:
value
nrc:general-reject : (integer-in 0 255)
value
nrc:service-not-supported : (integer-in 0 255)
value
nrc:sub-function-not-supported : (integer-in 0 255)
value
: (integer-in 0 255)
value
nrc:response-too-long : (integer-in 0 255)
value
nrc:busy-repeat-request : (integer-in 0 255)
value
nrc:conditions-not-correct : (integer-in 0 255)
value
nrc:request-sequence-error : (integer-in 0 255)
value
value
: (integer-in 0 255)
value
nrc:request-out-of-range : (integer-in 0 255)
value
nrc:security-access-denied : (integer-in 0 255)
value
nrc:authentication-required : (integer-in 0 255)
value
nrc:invalid-key : (integer-in 0 255)
value
nrc:exceed-number-of-attempts : (integer-in 0 255)
value
value
value
nrc:secure-data-transmission-not-allowed : (integer-in 0 255)
value
value
nrc:ownership-verification-failed : (integer-in 0 255)
value
nrc:challenge-calculation-failed : (integer-in 0 255)
value
nrc:setting-access-rights-failed : (integer-in 0 255)
value
nrc:session-key-creation-derivation-failed : (integer-in 0 255)
value
value
nrc:de-authentication-failed : (integer-in 0 255)
value
nrc:upload-download-not-accepted : (integer-in 0 255)
value
nrc:transfer-data-suspended : (integer-in 0 255)
value
nrc:general-programming-failure : (integer-in 0 255)
value
nrc:wrong-block-sequence-counter : (integer-in 0 255)
value
: (integer-in 0 255)
value
: (integer-in 0 255)
value
nrc:service-not-supported-in-active-session : (integer-in 0 255)
value
nrc:rpm-too-high : (integer-in 0 255)
value
nrc:rpm-too-low : (integer-in 0 255)
value
nrc:engine-is-running : (integer-in 0 255)
value
nrc:engine-is-not-running : (integer-in 0 255)
value
nrc:engine-run-time-too-low : (integer-in 0 255)
value
nrc:temperature-too-high : (integer-in 0 255)
value
nrc:temperature-too-low : (integer-in 0 255)
value
nrc:vehicle-speed-too-high : (integer-in 0 255)
value
nrc:vehicle-speed-too-low : (integer-in 0 255)
value
nrc:throttle-pedal-too-high : (integer-in 0 255)
value
nrc:throttle-pedal-too-low : (integer-in 0 255)
value
value
nrc:transmission-range-not-in-gear : (integer-in 0 255)
value
nrc:brake-switch-not-closed : (integer-in 0 255)
value
nrc:shifter-lever-not-in-park : (integer-in 0 255)
value
nrc:torque-converter-clutch-locked : (integer-in 0 255)
value
nrc:voltage-too-high : (integer-in 0 255)
value
nrc:voltage-too-low : (integer-in 0 255)
value
4 Diagnostic trouble codes
struct
number : (integer-in 0 65535) status-byte : (integer-in 0 255)
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?
procedure
(dtc-text->number s) → (integer-in 0 65535)
s : string?
procedure
(dtc-number->text n) → string?
n : (integer-in 0 65535)
procedure
(parse-dtc-records payload) → (listof dtc?)
payload : bytes?
procedure
(make-dtc-status [ #:test-failed test-failed #:test-failed-this-operation-cycle test-failed-this-operation-cycle #:pending pending #:confirmed confirmed #:test-not-completed-since-last-clear test-not-completed-since-last-clear #:test-failed-since-last-clear test-failed-since-last-clear #:test-not-completed-this-operation-cycle test-not-completed-this-operation-cycle #:warning-indicator-requested warning-indicator-requested]) → dtc-status? test-failed : boolean? = #f test-failed-this-operation-cycle : boolean? = #f pending : boolean? = #f confirmed : boolean? = #f test-not-completed-since-last-clear : boolean? = #f test-failed-since-last-clear : boolean? = #f test-not-completed-this-operation-cycle : boolean? = #f warning-indicator-requested : boolean? = #f
procedure
(dtc-status->byte s) → (integer-in 0 255)
s : dtc-status?
procedure
(byte->dtc-status b) → dtc-status?
b : (integer-in 0 255)
value
+dtc-group-all+ : (integer-in 0 16777215)
5 Requests
struct
sid : (integer-in 0 255) sub-function : (or/c #f (integer-in 0 127)) suppress? : boolean? data : bytes?
procedure
(request-parse payload) → request?
payload : bytes?
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? = #""
procedure
(diagnostic-session-control type [ #:suppress? suppress?]) → bytes? type : (or/c 'default 'programming 'extended (integer-in 0 127)) suppress? : boolean? = #f
procedure
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)
procedure
(read-dtc-by-status-mask mask) → bytes?
mask : (integer-in 0 255)
procedure
mask : (integer-in 0 255)
procedure
(report-supported-dtc [#:suppress? suppress?]) → bytes?
suppress? : boolean? = #f
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?
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?
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? = #""
procedure
(encode-address-and-length address address-bytes size size-bytes) → bytes? address : integer? address-bytes : (integer-in 1 15) size : integer? size-bytes : (integer-in 1 15)
procedure
(decode-address-and-length payload) →
integer? integer? payload : bytes?
6 Responses
procedure
(response-parse payload)
→ (or/c positive-response? negative-response?) payload : bytes?
struct
(struct positive-response (sid sub-function data))
sid : (integer-in 0 255) sub-function : (or/c #f (integer-in 0 127)) data : bytes?
Record decoders for the common positive responses. Each takes the positive-response-data byte string and returns the decoded fields; length mismatches raise.
procedure
(session-control-response data) →
(integer-in 0 255) exact-nonnegative-integer? exact-nonnegative-integer? data : bytes?
procedure
(security-seed-response data) → bytes?
data : bytes?
procedure
(max-block-length-response data) → exact-nonnegative-integer?
data : bytes?
procedure
(number-of-dtc-response data) →
(integer-in 0 255) exact-nonnegative-integer? data : bytes?
procedure
(dtc-list-response data) → (listof dtc?)
data : bytes?
procedure
(transfer-data-response data) →
(integer-in 0 255) bytes? data : bytes?
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.