Reading the ID: the 29-bit split
Classic CAN gives an 11-bit identifier; the extended format gives 29. On a car those extra
bits are mostly unused. J1939 instead assigns every one of them a job, so the ID itself is a
small structured record. Take the running example 0CF00400 apart from the top:
The top 3 bits are the priority. 0C in the first hex digit pair is
0000 1100 in binary, and the ID is only 29 bits wide, so the priority sits in
bits 28 to 26: 011, priority 3. Lower wins arbitration, exactly as raw CAN IDs
do; 0 is the most urgent and 6 is the default for routine broadcasts.
Two single bits follow: the Extended Data Page (reserved, and 0 on a J1939 bus)
and the Data Page, which becomes bit 16 of the PGN (counting from 0). Then come three whole bytes:
PDU Format F0, PDU Specific 04, and Source Address 00.
The source address is the simplest of the three: it is the sender's claimed bus address,
and 00 is the standard address of Engine #1. Which leaves the two bytes in
the middle, and those are where the interesting rule lives.
PDU1 vs PDU2: one byte, two jobs
J1939 messages are named by their PGN (Parameter Group Number), and the
PGN comes out of the PDU Format and PDU Specific bytes. But the PDU Specific byte means two
different things depending on the PDU Format value, and the cutoff is 240 (0xF0):
If PDU Format is below 240 (called PDU1), the message is addressed to one node: PDU Specific
is a destination address, and the PGN is just the PDU Format byte shifted up
(PF << 8, low byte zero). If PDU Format is 240 or above (PDU2), there is
no destination, the frame is a broadcast for anyone who cares, and PDU Specific becomes a
Group Extension that is part of the PGN itself (PF << 8 | PS).
In 0CF00400, PDU Format is F0, exactly at the cutoff, so this is
PDU2: broadcast, and the PGN is 0xF004, decimal 61444. That number has a name
in SAE J1939-71: EEC1, Electronic Engine Controller 1, the message that carries engine
speed. No request needed, no destination, the engine just shouts it onto the bus every few
tens of milliseconds.
EA), sent by a tool at address F9 to the
engine at 00, asking it to send PGN 65260 (the VIN). The 3-byte payload is
the requested PGN, little-endian.
Note what changed in the decoder: with PDU Format below 240, the blue byte flipped from "Group Extension" to "Destination", and the PGN's low byte went to zero. That one comparison (PF < 240) is the single most load-bearing rule in J1939 ID parsing.
SPNs: from bytes to physical values
Inside a PGN's 8 data bytes live SPNs (Suspect Parameter Numbers), the
individual signals. Each SPN has a fixed position, width, scale and offset, published in
J1939-71 (unlike a car's proprietary DBC, the dictionary is standard, which is why one
J1939 tool works across truck brands). Decode the running example's payload
FF FF 7D 68 13 00 FF FF by hand. J1939-71 counts data bytes from 1, and so
does this page:
Engine speed is SPN 190: bytes 4 and 5, 16 bits little-endian, 0.125 rpm per bit. Bytes 4
and 5 are 68 13, so the raw value is 0x1368 = 4968, and
4968 × 0.125 = 621 rpm. An idling diesel. Byte 3 is the actual engine
torque, one byte with a −125 offset: 0x7D = 125, 125 − 125 = 0 % torque, which
is what idle should read.
And the FF bytes are not garbage. J1939-71 reserves the top of every SPN's range,
judged by the value's most significant byte: up to FA is a real value,
FB is a parameter-specific indicator, FC-FD are
reserved, FE means error and FF means not
available (so 0xFFxx for a word). This ECU simply doesn't populate those
signals, and a decoder must show "n/a" rather than a nonsense value. The decoder above
greys them out for exactly that reason. A 2-bit status works the same way in miniature:
00 off, 01 on, 10 error, 11 not available.
5A = 90 − 40 = 50 °C, and an oil temperature scaled
at 1/32 °C per bit with a −273 offset (yes, it counts from absolute zero).
00 50 little-endian is
0x5000 = 20480, ÷ 256 = 80 km/h.
When 8 bytes aren't enough: the Transport Protocol
A VIN is 17 characters and a frame holds 8 bytes, so J1939 needs its own multi-frame layer
(it predates ISO-TP and works differently: the length and the carried PGN are announced in a
separate message rather than in a first-frame header). Two PGNs do all the work. TP.CM
(PGN 60416, PDU Format EC) manages the connection, and TP.DT
(PGN 60160, PDU Format EB) carries the data, 7 bytes per frame after a 1-byte
sequence number. That 7-byte stride caps a message at 255 packets × 7 = 1785 bytes.
For broadcasts there is no handshake at all. The sender transmits a single TP.CM with
control byte 0x20, a BAM (Broadcast Announce Message), saying
"a message of this size and PGN is coming in this many packets", then streams the TP.DT
frames with 50 to 200 ms between them. Receivers reassemble or ignore; nobody replies.
Point-to-point transfers use the same TP.DT frames but wrap them in an RTS/CTS handshake
(control bytes 0x10/0x11, closed by an End-of-Message ACK
0x13), which lets the receiver pace the sender the way ISO-TP flow control does.
Type a VIN below and watch the BAM sequence build. Hover the bytes: the TP.CM payload packs the control byte, the total size (little-endian), the packet count, and the PGN being carried (also little-endian, 3 bytes).
Who's talking: addresses and the address claim
Every sender needs a source address, and J1939 hands them out two ways. Well-known functions have fixed addresses from SAE J1939 (0 Engine #1, 3 Transmission #1, 11 Brakes - System Controller, 23 Instrument Cluster #1, and so on up through the standard list; 249 is the customary service-tool address, 255 is the global broadcast destination, 254 the null address). Everything else claims one at startup: the device broadcasts PGN 60928, Address Claimed, whose 8-byte payload is a 64-bit NAME encoding who it is (manufacturer code, function, industry group, a unique identity number). If two devices claim the same address, the one with the numerically lower NAME wins and the loser must claim a different address or fall silent. The result is plug-and-play addressing with no central allocator, which is why the same standard scaled from trucks to boats (NMEA 2000) and tractors (ISOBUS).
FF, source 00. The payload is the 64-bit
NAME; the decoder breaks out its fields.
Practical notes
The classic J1939 bus runs at 250 kbit/s (J1939-14 later added a 500 kbit/s profile), so set the speed before connecting a real adapter. In sloppyCAN, the J1939 / N2K tab does live what this page does statically: it splits every 29-bit ID, names the PGN, decodes the SPNs, reassembles TP transfers, and tracks address claims. The Demo button generates J1939 traffic (engine, cruise-control, electrical and driver-demand groups plus an engine address claim) so you can watch the PGN monitor with no hardware attached.
One honest caveat: the J1939-71 dictionary is huge, and this page decodes the same few dozen parameter groups the app does (it loads the app's own table). An ID that parses cleanly but shows "not in sloppyCAN's J1939 dictionary" is still a perfectly valid J1939 frame; the split and the PDU1/PDU2 rule apply to every 29-bit ID on the bus.