EDUCATION BUILD // NOT SAFETY-CERTIFIED // SYNTHETIC DEMO DATAEmbedded32 is for learning and prototyping - not automotive-certified, safety-certified, or a complete SAE J1939 stack.
Embedded32
Menu

J1939 concepts

SAE J1939 is a higher-layer protocol on CAN used in commercial vehicles. Embedded32 implements an educational subset: ID parsing, common PGN decoding, and simulation-friendly APIs - not a complete certified stack.

29-bit identifier layout

flowchart LR
  subgraph id29 [29-bit CAN ID]
    P["Priority (3)"]
    R["Reserved (1)"]
    DP["Data Page (1)"]
    PF["PDU Format (8)"]
    PS["PDU Specific (8)"]
    SA["Source Address (8)"]
  end
  P --> R --> DP --> PF --> PS --> SA

Embedded32 exposes this via parseJ1939Id and buildJ1939Id:

import { parseJ1939Id, buildJ1939Id } from '@embedded32/j1939';

const parsed = parseJ1939Id(0x18f00401);
// priority, pgn, sourceAddress, ...

const id = buildJ1939Id({ priority: 6, pgn: 0xf004, sourceAddress: 0x01 });

PGN and SPN

TermMeaning
PGN (Parameter Group Number)Identifies a message type (e.g. engine speed broadcast)
SPN (Suspect Parameter Number)Identifies a field within a PGN payload
flowchart TB
  FRAME[CAN frame]
  ID[29-bit ID → PGN + SA]
  DEC[decodeJ1939]
  PGN[PGN catalog entry]
  SPN[SPN fields]
  FRAME --> ID --> DEC --> PGN --> SPN

Use decodeJ1939(frame) for human-readable output and getPGNInfo(pgn) for catalog metadata.

PDU formats (conceptual)

PDU typePF rangePS meaning
PDU10–239Destination address
PDU2240–255Group extension (broadcast-style)

Labs focus on common broadcast PGNs (PDU2-style) found in the basic truck profile.

Encode vs decode

  • Decode - given a received frame, extract SPN values (implemented for catalog PGNs).
  • Encode - build payload bytes from logical values (partial - check package API for supported PGNs).

Always set extended: true on the CAN frame when exercising J1939.

Example walkthrough

import { MockCANDriver, CANInterface } from '@embedded32/can';
import { decodeJ1939, parseJ1939Id } from '@embedded32/j1939';

const can = new CANInterface(new MockCANDriver());
can.onMessage((frame) => {
  const msg = decodeJ1939(frame);
  console.log(msg.name, msg.signals);
});

const id = 0x18fef100; // example cruise/speed-related broadcast
can.send({ id, data: [0x40, 0x1f, 0, 0, 0, 0, 0, 0], extended: true });
console.log(parseJ1939Id(id));

Run the full example: npx tsx examples/j1939-basic.ts

Transport protocol (scope note)

Full J1939 uses Transport Protocol (BAM, RTS/CTS) for multi-packet messages. Embedded32 v1.0 documents this conceptually but does not claim full transport coverage for all PGNs. Single-frame PGNs are the primary lab focus.

Address claiming

J1939 nodes claim source addresses on the bus. Simulation profiles assign fixed addresses (e.g. engine 0x00, transmission 0x03) for predictable classroom output.

Honest limitations

  • PGN catalog is partial - enough for labs, not exhaustive
  • No compliance testing against SAE conformance suites
  • Bit-packed SPN scaling follows simplified rules in places - verify against SAE PDFs for research work

See also