Let's focus in on the ISO 15765-4 standard now, which is what all cars sold since 2008 are providing over the OBD-II port. This is using a CAN bus for the data link layer, which is very simple to work with.
According to ISO 15765-4, the DLC must provide power, ground, and CAN-H and CAN-L pins. Those are pins 16, 4, 6 and 14, respectively. A note on grounds: pin 4 is chassis ground, and pin 5 is signal ground, but I do not know if those are ever actually different.
CAN is a simple, elegant network communication layer. It is broadcast based, which means every message that is written to the bus is seen by everyone. It is up to everyone listening on the bus to decide if that message is meant for them. Sometimes, the message is meant for multiple ECUs on the bus.
There are 2-different CAN variants today, one with 11-bit message identifiers, and one with 29-bit message identifiers. Otherwise they're effectively the same. When a message is sent to the CAN bus, you provide a message id and then the payload of the message. If you asked for the right thing, you'll get a message back with a well-known id and expected format.
Note: I'll continue to use the term "scan tool" but that is an over-simplification of what is happening. It is the generic term for any device connecting to the OBD-II port to collect data or to give the car new data.
For ISO 15765-4 specific messages, it works like this: messages are 8-bytes long. The scan tool sends a message using CAN message identifier $7DF, which is the standard-defined identifier for diagnostic requests. The scan tool expects a response back from message identifiers in the range of $7E8 to $7EF, which allow multiple ECUs to respond to a single request.
Let's say we want to ask for the engine coolant temperature, the message would look like this (all values in hexadecimal format, with spaces between sections):
0x7df 0x02 0x01 0x05 0x00 0x00 0x00 0x00 0x00
- The first 11-bits is the CAN message identifier.
- The 1st byte is the number of additional bytes in this message, in this case, only 2.
- The 2nd byte is the type of request, or 'mode' - 0x01 is 'current data', 0x02 is 'freeze frame data', etc. This is the biggest single control factor on what type of message is being sent.
- The 3rd byte is the PID code, where PID standards for Parameter Identifier. This is what most people are after when they talk about PID codes. PID codes are well-defined, but also allow the manufacturer to provide their own extended codes.
- The remainder of the bytes are either zeros or not sent at all.
The response that comes back has a well-defined format, depending upon the type of PID being requested. There is usually some math involved as well as unit conversions, but there are only a handful of different types of data format that are expected, and the standard defined PIDs are small in number.
In our example above, we would expect a response that looks something like this (later I'll actually go get this from the Jeep to get real data):
0x7e8h 0x03 0x41 0x05 0x2a
The formula for calculating the coolant temperature is A - 40, with the result in degrees Celsius. In the example above, 0x2a is 42 in base-10, so the result would be 2ºC, or 36ºF.