lin:   Local Interconnect Network frames
1 Quick start
2 Protected identifiers
protected-id
frame-id
pid-valid?
3 Checksums
checksum-classic
checksum-enhanced
checksum-valid-classic?
checksum-valid-enhanced?
4 Frames
lin-frame
frame
frame-bytes
parse-frame
frame-bits
5 Diagnostic frames
diagnostic-request
diagnostic-response
diagnostic-parse
6 License
9.3

lin: Local Interconnect Network frames🔗ℹ

turinglambdaai

 (require lin) package: lin

The "lin" package implements the frame layer of LIN (Local Interconnect Network, ISO 17987) — the low-cost single-wire bus that sits under CAN in every vehicle for window lifts, seats, mirrors and other slave devices.

Everything is implemented in pure Racket. The 64-entry protected-ID table and the checksum vectors (including the LIN specification 2.2A §2.8.3 example calculation) are frozen from the public stm8-lin-checksum implementation as test fixtures.

1 Quick start🔗ℹ

Examples:
> (protected-id 1)

193

> (protected-id 60)

60

> (checksum-classic (bytes 74 85 147 229))

230

> (checksum-enhanced 191 (bytes 74 85 147 229))

39

> (define f (frame (protected-id 17) (bytes 74 85 147 229)))
> (frame-bytes f)

#"U\21JU\223\345\325"

> (parse-frame (frame-bytes f))

(lin-frame 17 #"JU\223\345" 213 'enhanced)

2 Protected identifiers🔗ℹ

A LIN frame is addressed by a 6-bit ID; on the wire it carries two parity bits in the high positions: P0 = ID0^ID1^ID2^ID4 (even) and P1 = !(ID1^ID3^ID4^ID5) (odd).

procedure

(protected-id id) → (integer-in 0 255)

  id : (integer-in 0 63)
The protected ID for a frame ID. Diagnostic IDs 60/61 keep their bare values (their parity bits are 0).

procedure

(frame-id pid) → (integer-in 0 63)

  pid : (integer-in 0 255)
The frame ID carried by a PID (parity bits masked off).

procedure

(pid-valid? pid) → boolean?

  pid : (integer-in 0 255)
Do the parity bits of pid match its frame ID?

3 Checksums🔗ℹ

The LIN checksum is an inverted 8-bit sum with carry folding: each overflow adds 1 back to the low byte, and the final sum is inverted. The classic form (LIN 1.x) covers the data bytes only; the enhanced form (LIN 2.x) starts from the protected ID. Diagnostic frames (IDs 60/61) always use the classic form.

procedure

(checksum-classic data) → (integer-in 0 255)

  data : bytes?

procedure

(checksum-enhanced pid data) → (integer-in 0 255)

  pid : (integer-in 0 255)
  data : bytes?

procedure

(checksum-valid-classic? cksum data) → boolean?

  cksum : (integer-in 0 255)
  data : bytes?

procedure

(checksum-valid-enhanced? cksum pid data) → boolean?

  cksum : (integer-in 0 255)
  pid : (integer-in 0 255)
  data : bytes?

4 Frames🔗ℹ

struct

(struct lin-frame (pid data checksum kind))

  pid : (integer-in 0 255)
  data : bytes?
  checksum : (integer-in 0 255)
  kind : (or/c 'classic 'enhanced)
One frame: the protected ID, 0-8 data bytes, the checksum and its kind.

procedure

(frame pid    
  data    
  #:kind kind    
  #:checksum checksum) → lin-frame?
  pid : (integer-in 0 255)
  data : bytes?
  kind : (or/c 'classic 'enhanced)
  checksum : (or/c (integer-in 0 255) #f)
Builds a frame; the checksum defaults to the computed value for the kind. Diagnostic frames (IDs 60/61) are forced to the classic kind. Invalid parity, more than 8 data bytes — errors.

procedure

(frame-bytes f) → bytes?

  f : lin-frame?
The on-wire byte sequence: sync (0x55), PID, data, checksum. The BREAK field is a UART-level artifact handled by the transport and is not part of these bytes.

procedure

(parse-frame bs [#:kind kind]) → lin-frame?

  bs : bytes?
  kind : (or/c 'classic 'enhanced) = 'enhanced
Parses and validates a frame byte sequence: the sync byte must be 0x55, the PID parity must hold, and the checksum must match (diagnostic frames are always checked as classic). Violations raise exn:fail.

procedure

(frame-bits data-length) → exact-nonnegative-integer?

  data-length : exact-nonnegative-integer?
The on-wire bit count of a complete frame: the 13-bit break plus delimiter and 10 bits (start + 8 data + stop) per byte of sync, PID, data and checksum — for timing estimates at the 1-20 kbit/s LIN rates.

5 Diagnostic frames🔗ℹ

IDs 60 (master request) and 61 (slave response) always carry 8 data bytes: NAD, PCI, SID/RSID and payload; the PCI of a single-frame diagnostic is 0x0N with N the number of bytes after the PCI.

procedure

(diagnostic-request nad sid payload) → lin-frame?

  nad : (integer-in 0 255)
  sid : (integer-in 0 255)
  payload : bytes?
A master request frame (ID 60): NAD, PCI, SID and up to 5 data bytes.

procedure

(diagnostic-response nad rsid payload) → lin-frame?

  nad : (integer-in 0 255)
  rsid : (integer-in 0 255)
  payload : bytes?
A slave response frame (ID 61): NAD, PCI, RSID and up to 5 data bytes.

The NAD, PCI and remaining bytes of an 8-byte diagnostic payload.

6 License🔗ℹ

MIT. Test fixtures derive from stm8-lin-checksum (MIT).