obd2:   SAE J1979 OBD-II services
1 Quick start
2 The PID table
pid
mode-01-pids
pid-for
3 Decoding
decode-pid
status-word
supported-pids
parse-freeze-dtc
parse-dtcs
4 Services
obd-response
make-request
parse-response
vin-from-response
5 License
9.3

obd2: SAE J1979 OBD-II services🔗ℹ

turinglambdaai

 (require obd2) package: obd2

The "obd2" package implements the message layer of OBD-II — the SAE J1979 diagnostic services ("modes") that every road vehicle sold in major markets must answer: live sensor PIDs, stored and pending diagnostic trouble codes, freeze frames, vehicle information and emissions readiness.

Everything is implemented in pure Racket. The Mode 01 PID table is a frozen port of the Python python-OBD library (0.7.3), whose live decoders also provide the arithmetic test anchors. DTC text forms are shared with the uds package.

1 Quick start🔗ℹ

Examples:
> (make-request 1 12)

#"\1\f"

> (define r (parse-response 1 (bytes 65 12 14 112)))
> (obd-response-pid r)

12

> (obd-response-value r)

'(924.0 . "rpm")

> (decode-pid (pid-for 0) (bytes 190 31 168 19))

'(1 3 4 5 6 7 12 13 14 15 16 17 19 21 28 31 32)

2 The PID table🔗ℹ

struct

(struct pid (number name data-bytes decode))

  number : exact-nonnegative-integer?
  name : string?
  data-bytes : (integer-in 0 255)
  decode : symbol?
One Mode 01 parameter: its J1979 number, python-OBD name, response payload length (after the mode and PID echo bytes) and the decode kind naming a formula in decode-pid.

All 96 Mode 01 PIDs of the standard table (00 through 5F).

procedure

(pid-for number) → (or/c pid? #f)

  number : exact-nonnegative-integer?
The table entry for number, or #f.

3 Decoding🔗ℹ

procedure

(decode-pid p payload)

 → 
(or/c pair? exact-integer? boolean? string? (listof exact-integer?) #f
      (listof (or/c string? #f)))
  p : pid?
  payload : bytes?
Decodes a response payload (after the mode and PID echo) according to the entry’s kind. Arithmetic decoders return (cons value unit) with the J1979 formulas (RPM /4, MAF /100, temperatures -40, equivalence ratio /32768, ...); symbolic decoders return:

  • 'supported-pids and 'o2-presence — the list of PID numbers declared by a 32-bit bitmap;

  • 'status / 'monitor-status — (list* mil-on? dtc-count ignition-type) via status-word;

  • 'freeze-dtc — the DTC text (e.g. "P0420") or #f;

  • 'fuel-status / 'air-status / 'obd-compliance / 'fuel-type — the J1979 text tables, with #f for invalid or out-of-range entries.

procedure

(status-word data)

 → (list* boolean? exact-nonnegative-integer? list?)
  data : bytes?
The MIL/DTC word of PIDs 01 and 41: MIL on?, the DTC count (A & 0x7F) and 'spark / 'compression / 'reserved from B.

procedure

(supported-pids base bitmap)

 → (listof exact-nonnegative-integer?)
  base : exact-nonnegative-integer?
  bitmap : bytes?
The PIDs declared by a 32-bit bitmap whose MSB is (+ base 1).

procedure

(parse-freeze-dtc data) → (or/c string? #f)

  data : bytes?
The single PID 02 DTC in the 16-bit letter form, or #f for zeros.

procedure

(parse-dtcs data) → (listof string?)

  data : bytes?
The 2-byte DTC list of modes 03, 07 and 0A. An odd-length payload is prefixed by the DTC count byte; 0000 pairs are padding. Letters decode through uds’s dtc-number->text: 0x0420 → "P0420".

4 Services🔗ℹ

struct

(struct obd-response (mode pid negative? nrc value))

  mode : exact-nonnegative-integer?
  pid : (or/c exact-nonnegative-integer? #f)
  negative? : boolean?
  nrc : (or/c exact-nonnegative-integer? #f)
  value : any/c
One parsed response: the requested mode, the echoed PID (modes 01/02), whether the ECU answered negatively (7F <mode> <nrc>), the negative response code, and the decoded value (modes 01/02), DTC text list (modes 03/07/0A) or raw payload (other modes).

procedure

(make-request mode pid) → bytes?

  mode : exact-nonnegative-integer?
  pid : exact-nonnegative-integer?
The request bytes: the mode, optionally followed by the PID.

procedure

(parse-response mode data) → obd-response?

  mode : exact-nonnegative-integer?
  data : bytes?
Parses and decodes a response. The echo must equal mode + 0x40 (or a negative response must start with 7F); violations — and unknown PIDs or short payloads — raise exn:fail.

procedure

(vin-from-response data) → string?

  data : bytes?
The VIN from a service 09, info type 02 response. The 49 02 N line headers are stripped wherever they appear (a VIN cannot contain the 0x02 byte, so the scan is unambiguous) and the rest is read as ASCII.

5 License🔗ℹ

MIT. The PID table is ported from python-OBD (MIT).