Last modified:
J2534 (often referred to as Pass-Thru) is a standard developed by SAE (Society of Automotive Engineers) that solves an important problem: it allows the same diagnostic software to work with diagnostic adapters from different manufacturers.
The main idea:
Imagine you are writing a car diagnostics application. Without the J2534 standard, you would have to write unique code for each adapter (K-Line, CAN adapter, etc.) you want to support. This is complex and expensive.
The J2534 standard defines a unified API (Application Programming Interface) that adapter manufacturers must implement in their drivers. The standard defines this API as a DLL library for Windows only.
For a developer, this means:
PassThruOpen, PassThruReadMsg).Thus, J2534 is a "bridge" between your application and the diagnostic adapter that hides the complexities of specific hardware and allows you to focus on the diagnostics logic.
Many developers, beyond Windows, want to use alternative platforms. In addition to the standard DLL for Windows, we also provide libraries for Linux, macOS, as well as the mobile platforms Android and iOS.
It is important to understand that J2534 is a standard for the transport layer. It handles all the work of sending and receiving data bytes over the selected physical interface (CAN, K-Line, etc.).
However, the J2534 standard does not define:
This remains the task of your application. As a developer, you need to know which specific bytes to send to request, for example, fault codes or current parameters, and how to parse the response from the control unit.
For this, you will need knowledge of application-level diagnostic protocols, such as:
The J2534 DLL will deliver your bytes to the ECU, but what those bytes are and what to do with the response is determined by your application.
The J2534 standard is part of a large family of standards governing automotive diagnostics. For a deeper understanding, it is recommended to review the official documents.
Detailed table of protocol and standard relationships
The ScanDoc adapter implements a partial version of the J2534-1 standard and some extensions from J2534-2, and also has its own functions for extending capabilities.
The J2534 standard defines a set of physical and transport layer protocols through which data is exchanged with the vehicle's ECU. Each protocol supported by the ScanDoc adapter is described below.
The primary protocol for diagnostics of modern vehicles. ISO 15765 (also known as ISO-TP) implements a transport layer on top of the CAN bus: it automatically performs segmentation of long messages into CAN frames, flow control management, and reassembly of responses from multiple frames.
This is the protocol used for diagnostics via UDS (ISO 14229) and OBD-II on the CAN bus. If your task is to send diagnostic requests and receive responses from the ECU, use ISO15765.
CAN_29BIT_IDFLOW_CONTROL_FILTER (up to 16 per channel)ISO15765_ADDR_TYPE// Connect via ISO 15765 at 500 kbit/s
PassThruConnect(deviceID, ISO15765, 0, 500000, &channelID);
The CAN protocol provides access to the raw stream of CAN frames without a transport layer. Each message is a single CAN frame (up to 8 bytes of data). The adapter does not perform segmentation or reassembly — you receive and send frames as-is.
Use this protocol when you need to work with the CAN bus directly: traffic monitoring, sending individual frames, working with non-standard protocols on top of CAN.
CAN_29BIT_IDPASS_FILTER and BLOCK_FILTER (up to 10 of each type)// Connect CAN at 500 kbit/s with 29-bit IDs
PassThruConnect(deviceID, CAN, CAN_29BIT_ID, 500000, &channelID);
A K-line diagnostic protocol, widely used in vehicles from the 2000s (especially European). It supports two methods of connection initialization: 5-baud (slow) and fast init. After initialization, communication proceeds at the speed negotiated with the ECU.
Used for dealer-level diagnostics via KWP2000 and for OBD-II on the K-line.
FIVE_BAUD_INIT) or fast (FAST_INIT) via PassThruIoctlISO9141_K_LINE: if set, initialization uses K-line only (without L-line)SET_CONFIG// Connect via ISO 14230 at 10400 baud, K-line only
PassThruConnect(deviceID, ISO14230, ISO9141_K_LINE, 10400, &channelID);
An earlier K-line protocol, defined by the ISO 9141-2 standard. Used for OBD-II diagnostics in older vehicles (before 2004-2008 depending on region). Supports only 5-baud initialization.
FIVE_BAUD_INIT// Connect via ISO 9141 at 10400 baud
PassThruConnect(deviceID, ISO9141, 0, 10400, &channelID);
A protocol using Variable Pulse Width modulation, used in General Motors vehicles for OBD-II diagnostics. Operates at 10.4 kbit/s over a single wire.
// Connect via J1850 VPW
PassThruConnect(deviceID, J1850VPW, 0, 10400, &channelID);
A protocol using Pulse Width Modulation, used in Ford vehicles for OBD-II diagnostics. Operates at 41.6 kbit/s over two wires.
// Connect via J1850 PWM
PassThruConnect(deviceID, J1850PWM, 0, 41600, &channelID);
Working with a J2534 adapter from your application typically follows this algorithm:
Each J2534 adapter manufacturer provides their own API implementation as a DLL file. When the driver is installed, information about this DLL (file path) is written to the Windows registry.
Your application should:
LoadLibrary function (on Windows).After loading the DLL and obtaining function pointers, a typical diagnostic session looks like this:
PassThruOpen() function to initialize communication with the physical device. In response, you will receive a DeviceID — a unique identifier for this session.
// Example
unsigned long deviceID;
long result = PassThruOpen(NULL, &deviceID);
PassThruConnect() to establish a logical communication channel with the vehicle using a specific protocol (e.g., ISO15765 for the CAN bus). You specify
the protocol, speed, and other parameters. In response, you receive a ChannelID.
// Example
unsigned long channelID;
result = PassThruConnect(deviceID, ISO15765, 0, 500000, &channelID);
PassThruStartMsgFilter() function is used to create and configure filters.
The data exchange process is asynchronous and based on queues:
PassThruWriteMsg() does not send the message to the bus immediately. Instead, it places one or more messages into the send queue and returns control immediately.
The adapter driver will independently send these messages from the queue as soon as possible.PassThruReadMsg() function is used to retrieve messages from this queue.Important note: The J2534 library is single-threaded. This means that all function calls (PassThruWriteMsg, PassThruReadMsg, etc.) for a single channel must be executed strictly sequentially.
You cannot call one function while the previous one is still executing. Attempting to call functions simultaneously from different threads for the same channel will lead to unpredictable behavior.
PassThruDisconnect().
// Example
result = PassThruDisconnect(channelID);
PassThruClose() to release the device.
// Example
result = PassThruClose(deviceID);
This cycle is the foundation of any J2534 application. The following sections describe each API function and its parameters in detail.
Every J2534 API function returns a status code. Successful execution always returns STATUS_NOERROR (value 0). Any other value indicates a specific error (e.g., ERR_TIMEOUT, ERR_INVALID_CHANNEL_ID, etc.).
It is extremely important to check the return value after every function call.
A special error code is ERR_FAILED. This is a general, non-specific error. Only in this case should you call PassThruGetLastError() to obtain a more detailed, textual description of the problem from the driver.
// Example of proper error handling
long result = PassThruConnect(deviceID, ISO15765, 0, 500000, &channelID);
if (result != STATUS_NOERROR)
{
printf("PassThruConnect error. Code: %ld\n", result);
// If the error is general, request details
if (result == ERR_FAILED)
{
char errorDescription[80];
PassThruGetLastError(&errorDescription[0], 80);
printf(" Additional info: %s\n", errorDescription);
}
// Here you can add logic for handling other error codes
// switch (result) { case ERR_TIMEOUT: ... }
return; // Abort execution
}
A detailed description of each J2534 standard function is available in the functions reference.