Skip to content

AnonAuto/J2534

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 

Repository files navigation

ANONAUTOSTICKER

J2534

In 32 bit Python.

The Anonymous Automotive Alliance Presents 

         A J2534 Implementation.

          In 32 bit Python.

          Deployed 21/10/2025

       Communication is Essential.

    Without it what would we have?

J2534 Python Library

A comprehensive Python implementation of the SAE J2534 PassThru API for automotive diagnostics and ECU programming.

Table of Contents

Overview

The J2534 Python Library provides a complete Python interface to SAE J2534-compliant PassThru devices. J2534 is a standard API that allows software applications to communicate with vehicle Electronic Control Units (ECUs) through a PassThru device.

This library is a direct Python port from C#, maintaining exact naming conventions and structure for compatibility and ease of migration.

What is J2534?

J2534 (SAE J2534) is a standard that defines an interface between a computer application and a vehicle communication interface device. It enables:

  • Vehicle Diagnostics: Read and clear diagnostic trouble codes (DTCs)
  • ECU Programming: Flash and reprogram vehicle control modules
  • Data Logging: Monitor real-time vehicle data
  • Network Analysis: Analyze CAN, ISO-TP, and other automotive protocols

Features

  • âś… Complete J2534 API Implementation: Full support for all J2534 v04.04 and v05.00 functions
  • âś… Multiple Protocol Support: CAN, ISO15765, ISO9141, ISO14230, J1850 VPW/PWM, and more
  • âś… Extended Functions: Battery voltage reading, buffer management, configuration
  • âś… Type Safety: Extensive use of Python enums and type hints
  • âś… Cross-Platform: Works on Windows (with native J2534 DLLs) and can be extended for Linux
  • âś… Memory Management: Proper ctypes memory handling for safe native interop
  • âś… Exact C# Compatibility: Preserved naming conventions for easy migration

Requirements

System Requirements

  • Python 3.7 or higher
  • Windows OS (for native J2534 DLL support)
  • A J2534-compliant PassThru device and its driver DLL

Python Dependencies

  • ctypes (standard library)
  • enum (standard library)
  • typing (standard library)

No external dependencies required!

Installation

  1. Copy the J2534.py file to your project directory:
cp J2534.py /path/to/your/project/
  1. Import in your Python code:
from J2534 import *
  1. Ensure your J2534 device drivers are installed on your system.

Quick Start

Basic Connection Example

from J2534 import *

# Create a J2534 device instance
device = J2534Device()
device.Name = "My PassThru Device"
device.FunctionLibrary = "C:\\Path\\To\\J2534Device.dll"

# Create J2534 functions wrapper
j2534 = J2534Functions()

# Load the device library
if j2534.LoadLibrary(device):
    print("Library loaded successfully!")
    
    # Open device
    deviceId = c_uint(0)
    result = j2534.PassThruOpen(c_void_p(0), deviceId)
    
    if result == J2534Err.STATUS_NOERROR:
        print(f"Device opened with ID: {deviceId.value}")
        
        # Connect to CAN bus
        channelId = c_uint(0)
        result = j2534.PassThruConnect(
            deviceId.value,
            ProtocolID.ISO15765,
            ConnectFlag.NONE,
            BaudRate.ISO15765_500000,
            channelId
        )
        
        if result == J2534Err.STATUS_NOERROR:
            print(f"Connected to bus with channel ID: {channelId.value}")
            
            # Your diagnostic operations here...
            
            # Disconnect when done
            j2534.PassThruDisconnect(channelId.value)
        
        # Close device
        j2534.PassThruClose(deviceId.value)
    
    # Free library
    j2534.FreeLibrary()
else:
    print("Failed to load library!")

Sending a Message

# Create a message
msg = PassThruMsg(
    ProtocolID.ISO15765,
    TxFlag.NONE,
    bytes([0x00, 0x00, 0x07, 0xE0, 0x01, 0x00])  # Example OBD-II request
)

# Send the message
msgPtr = Utils.ToIntPtr(msg)
numMsgs = c_int(1)
timeout = 1000  # ms

result = j2534.PassThruWriteMsgs(
    channelId.value,
    msgPtr,
    numMsgs,
    timeout
)

if result == J2534Err.STATUS_NOERROR:
    print(f"Message sent successfully! {numMsgs.value} messages transmitted.")

Reading Messages

# Allocate memory for received messages
numMsgs = c_int(10)
rxMsgs = cast(create_string_buffer(sizeof(PassThruMsg) * numMsgs.value), c_void_p)
timeout = 1000  # ms

result = j2534.PassThruReadMsgs(
    channelId.value,
    rxMsgs,
    numMsgs,
    timeout
)

if result == J2534Err.STATUS_NOERROR:
    messages = Utils.AsMsgList(rxMsgs, numMsgs.value)
    
    for msg in messages:
        print(f"Received message: {msg.GetBytes().hex()}")

Architecture

Library Structure

J2534.py
├── Enumerations
│   ├── ConfigParameter       # Configuration parameters
│   ├── ProtocolID           # Communication protocols
│   ├── BaudRate             # Baud rate definitions
│   ├── J2534Err             # Error codes
│   ├── TxFlag               # Transmission flags
│   ├── RxStatus             # Reception status flags
│   ├── ConnectFlag          # Connection flags
│   ├── FilterType           # Message filter types
│   ├── PinNumber            # Pin numbering
│   ├── PinVoltage           # Voltage levels
│   ├── Ioctl                # IOCTL commands
│   └── GET_DEVICE_INFO_Defines
│
├── Interfaces
│   ├── IJ2534               # Base J2534 interface
│   └── IJ2534Extended       # Extended functionality
│
├── Core Classes
│   ├── J2534Device          # Device information
│   ├── J2534Functions       # Standard J2534 functions
│   ├── J2534FunctionsExtended # Extended functions
│   ├── J2534DllWrapper      # DLL loading and function pointers
│   └── J2534Exception       # Exception handling
│
├── Structures
│   ├── PassThruMsg          # Message structure
│   ├── SConfig              # Configuration structure
│   ├── SConfigList          # Configuration list
│   ├── SParam               # Parameter structure
│   ├── SParamList           # Parameter list
│   ├── SByteArray           # Byte array structure
│   ├── SDEVICE              # Device structure
│
└── Utilities
    ├── NativeMethods        # Native DLL interaction
    └── Utils                # Helper functions

API Reference

Core Classes

J2534Device

Represents a J2534 PassThru device.

class J2534Device:
    def __init__(self):
        self.Vendor = ""              # Device vendor name
        self.Name = ""                # Device name
        self.FunctionLibrary = ""     # Path to device DLL
        self.ConfigApplication = ""   # Configuration application path
        # Protocol support flags
        self.CAN = 0
        self.ISO14230 = 0
        self.ISO15765 = 0
        self.ISO9141 = 0
        self.J1850PWM = 0
        self.J1850VPW = 0
        # ... additional protocol flags

Properties:

  • Vendor (str): Manufacturer name
  • Name (str): Device model name
  • FunctionLibrary (str): Full path to the J2534 DLL
  • Protocol support properties indicate which protocols are supported (0 = not supported, >0 = supported)

J2534Functions

Main class for J2534 API operations.

class J2534Functions(IJ2534):
    def LoadLibrary(self, device: J2534Device) -> bool
    def FreeLibrary(self) -> bool
    
    def PassThruOpen(self, name: c_void_p, deviceId: c_uint) -> J2534Err
    def PassThruClose(self, deviceId: c_uint) -> J2534Err
    def PassThruConnect(self, deviceId: c_uint, protocolId: ProtocolID, 
                       flags: ConnectFlag, baudRate: BaudRate, 
                       channelId: c_uint) -> J2534Err
    def PassThruDisconnect(self, channelId: c_int) -> J2534Err
    
    def PassThruReadMsgs(self, channelId: c_int, msgs: c_void_p, 
                        numMsgs: c_int, timeout: c_int) -> J2534Err
    def PassThruWriteMsgs(self, channelId: c_int, msgs: c_void_p, 
                         numMsgs: c_int, timeout: c_int) -> J2534Err
    
    def PassThruStartPeriodicMsg(self, channelId: c_int, msg: c_void_p, 
                                msgId: c_int, timeInterval: c_int) -> J2534Err
    def PassThruStopPeriodicMsg(self, channelId: c_int, msgId: c_int) -> J2534Err
    
    def PassThruStartMsgFilter(self, channelid: c_int, filterType: FilterType,
                              maskMsg: c_void_p, patternMsg: c_void_p,
                              flowControlMsg: c_void_p, filterId: c_int) -> J2534Err
    def PassThruStopMsgFilter(self, channelId: c_int, filterId: c_int) -> J2534Err
    
    def PassThruSetProgrammingVoltage(self, deviceId: c_int, 
                                     pinNumber: PinNumber, 
                                     voltage: c_uint) -> J2534Err
    def PassThruReadVersion(self, deviceId: c_int, firmwareVersion: c_void_p,
                          dllVersion: c_void_p, apiVersion: c_void_p) -> J2534Err
    def PassThruGetLastError(self, errorDescription: c_void_p) -> J2534Err
    def PassThruIoctl(self, channelId: c_int, ioctlID: c_int, 
                     input: c_void_p, output: c_void_p) -> J2534Err

Key Methods:

LoadLibrary(device: J2534Device) -> bool

Loads the J2534 DLL specified in the device configuration.

Parameters:

  • device: J2534Device object with FunctionLibrary path set

Returns:

  • True if library loaded successfully
  • False if loading failed
PassThruOpen(name: c_void_p, deviceId: c_uint) -> J2534Err

Opens a communication connection to the PassThru device.

Parameters:

  • name: Reserved for future use (pass c_void_p(0))
  • deviceId: Reference to receive the device ID

Returns:

  • J2534Err.STATUS_NOERROR on success
  • Error code on failure
PassThruConnect(deviceId, protocolId, flags, baudRate, channelId) -> J2534Err

Establishes a logical communication channel using a specific protocol.

Parameters:

  • deviceId: Device ID from PassThruOpen
  • protocolId: Communication protocol (ProtocolID enum)
  • flags: Connection flags (ConnectFlag enum)
  • baudRate: Communication speed (BaudRate enum)
  • channelId: Reference to receive the channel ID

Returns:

  • J2534Err.STATUS_NOERROR on success
  • Error code on failure
PassThruWriteMsgs(channelId, msgs, numMsgs, timeout) -> J2534Err

Transmits messages on the specified channel.

Parameters:

  • channelId: Channel ID from PassThruConnect
  • msgs: Pointer to PassThruMsg array
  • numMsgs: Reference to number of messages (input/output)
  • timeout: Timeout in milliseconds

Returns:

  • J2534Err.STATUS_NOERROR on success
  • Error code on failure
PassThruReadMsgs(channelId, msgs, numMsgs, timeout) -> J2534Err

Receives messages from the specified channel.

Parameters:

  • channelId: Channel ID from PassThruConnect
  • msgs: Pointer to receive message array
  • numMsgs: Reference to number of messages (input/output)
  • timeout: Timeout in milliseconds

Returns:

  • J2534Err.STATUS_NOERROR on success
  • J2534Err.ERR_BUFFER_EMPTY if no messages available
  • Other error codes on failure

J2534FunctionsExtended

Extended functionality beyond the standard J2534 API.

class J2534FunctionsExtended(J2534Functions, IJ2534Extended):
    def GetConfig(self, channelId: c_int, config: List[SConfig]) -> J2534Err
    def SetConfig(self, channelId: c_int, config: List[SConfig]) -> J2534Err
    
    def ReadBatteryVoltage(self, deviceId: c_int, voltage: c_int) -> J2534Err
    def ReadProgrammingVoltage(self, deviceId: c_int, voltage: c_int) -> J2534Err
    
    def SW_CAN_BusSpeed(self, ChannelID: c_int, Option: c_int) -> J2534Err
    
    def FiveBaudInit(self, channelId: c_int, targetAddress: c_byte,
                    keyword1: c_byte, keyword2: c_byte) -> J2534Err
    def FastInit(self, channelId: c_int, txMsg: PassThruMsg, 
                rxMsg: PassThruMsg) -> J2534Err
    
    def ClearTxBuffer(self, channelId: c_int) -> J2534Err
    def ClearRxBuffer(self, channelId: c_int) -> J2534Err
    def ClearPeriodicMsgs(self, channelId: c_int) -> J2534Err
    def ClearMsgFilters(self, channelId: c_int) -> J2534Err
    
    def ReadAllMessages(self, channelId: c_int, numMsgs: c_int, 
                       timeout: c_int, messages: List[PassThruMsg],
                       readUntilTimeout: bool = True) -> J2534Err

Extended Methods:

GetConfig(channelId: c_int, config: List[SConfig]) -> J2534Err

Retrieves current configuration parameters.

Example:

config = [
    SConfig(ConfigParameter.DATA_RATE, 0),
    SConfig(ConfigParameter.LOOPBACK, 0)
]
result = j2534_ext.GetConfig(channelId.value, config)
if result == J2534Err.STATUS_NOERROR:
    print(f"Data Rate: {config[0].Value}")
    print(f"Loopback: {config[1].Value}")
SetConfig(channelId: c_int, config: List[SConfig]) -> J2534Err

Sets configuration parameters.

Example:

config = [
    SConfig(ConfigParameter.LOOPBACK, 1),  # Enable loopback
    SConfig(ConfigParameter.DATA_RATE, 500000)  # Set 500k baud
]
result = j2534_ext.SetConfig(channelId.value, config)
ReadBatteryVoltage(deviceId: c_int, voltage: c_int) -> J2534Err

Reads the vehicle battery voltage.

Example:

voltage = c_int(0)
result = j2534_ext.ReadBatteryVoltage(deviceId.value, voltage)
if result == J2534Err.STATUS_NOERROR:
    voltage_mv = voltage.value
    voltage_v = voltage_mv / 1000.0
    print(f"Battery Voltage: {voltage_v:.2f}V")
ReadAllMessages(channelId, numMsgs, timeout, messages, readUntilTimeout) -> J2534Err

Continuously reads messages until timeout or buffer empty.

Parameters:

  • channelId: Channel ID
  • numMsgs: Maximum messages to read per call
  • timeout: Timeout in milliseconds
  • messages: List to populate with received messages
  • readUntilTimeout: If True, read until timeout; if False, read one batch

Example:

messages = []
result = j2534_ext.ReadAllMessages(
    channelId.value,
    10,  # Read up to 10 messages at a time
    1000,  # 1 second timeout
    messages,
    readUntilTimeout=True
)

for msg in messages:
    print(f"Received: {msg.GetBytes().hex()}")

Enumerations

ProtocolID

Defines supported communication protocols.

class ProtocolID(IntEnum):
    J1850VPW = 0x01                # J1850 VPW (GM)
    J1850PWM = 0x02                # J1850 PWM (Ford)
    ISO9141 = 0x03                 # ISO 9141
    ISO14230 = 0x04                # ISO 14230 (KWP2000)
    CAN = 0x05                     # Raw CAN
    ISO15765 = 0x06                # ISO 15765 (ISO-TP/UDS)
    SCI_A_ENGINE = 0x07            # Chrysler SCI (Engine)
    SCI_A_TRANS = 0x08             # Chrysler SCI (Transmission)
    SCI_B_ENGINE = 0x09            # Chrysler SCI (Engine)
    SCI_B_TRANS = 0x0A             # Chrysler SCI (Transmission)
    ISO15765_LOGICAL = 0x200       # ISO 15765 Logical
    # J2534-2 protocols
    J1850VPW_PS = 0x8000           # J1850 VPW Passive
    J1850PWM_PS = 0x8001           # J1850 PWM Passive
    ISO9141_PS = 0x8002            # ISO 9141 Passive
    ISO14230_PS = 0x8003           # ISO 14230 Passive
    CAN_PS = 0x8004                # CAN Passive
    ISO15765_PS = 0x8005           # ISO 15765 Passive
    # ... additional protocols

J2534Err

Error codes returned by J2534 functions.

class J2534Err(IntEnum):
    STATUS_NOERROR = 0x00                      # Success
    ERR_NOT_SUPPORTED = 0x01                   # Function not supported
    ERR_INVALID_CHANNEL_ID = 0x02              # Invalid channel ID
    ERR_INVALID_PROTOCOL_ID = 0x03             # Invalid protocol ID
    ERR_NULL_PARAMETER = 0x04                  # NULL pointer supplied
    ERR_INVALID_FLAGS = 0x06                   # Invalid flags
    ERR_FAILED = 0x07                          # Undefined error
    ERR_ConnectedDevice_NOT_CONNECTED = 0x08   # Device not connected
    ERR_TIMEOUT = 0x09                         # Timeout
    ERR_INVALID_MSG = 0x0A                     # Invalid message
    ERR_INVALID_TIME_INTERVAL = 0x0B           # Invalid time interval
    ERR_EXCEEDED_LIMIT = 0x0C                  # Exceeded limit
    ERR_INVALID_MSG_ID = 0x0D                  # Invalid message ID
    ERR_ConnectedDevice_IN_USE = 0x0E          # Device in use
    ERR_INVALID_IOCTL_ID = 0x0F                # Invalid IOCTL ID
    ERR_BUFFER_EMPTY = 0x10                    # Buffer empty
    ERR_BUFFER_FULL = 0x11                     # Buffer full
    ERR_BUFFER_OVERFLOW = 0x12                 # Buffer overflow
    ERR_PIN_INVALID = 0x13                     # Invalid pin number
    ERR_CHANNEL_IN_USE = 0x14                  # Channel in use
    ERR_MSG_PROTOCOL_ID = 0x15                 # Protocol mismatch
    ERR_INVALID_FILTER_ID = 0x16               # Invalid filter ID
    ERR_NO_FLOW_CONTROL = 0x17                 # No flow control filter
    ERR_NOT_UNIQUE = 0x18                      # Not unique
    ERR_INVALID_BAUDRATE = 0x19                # Invalid baud rate
    ERR_INVALID_ConnectedDevice_ID = 0x1A      # Invalid device ID
    # ... additional error codes

BaudRate

Common baud rate values for different protocols.

class BaudRate(IntEnum):
    ISO9141_10400 = 10400
    ISO9141_10000 = 10000
    ISO14230_10400 = 10400
    ISO14230_10000 = 10000
    J1850PWM_41600 = 41600
    J1850PWM_83300 = 83300
    J1850VPW_10400 = 10400
    J1850VPW_41600 = 41600
    CAN_125000 = 125000
    CAN_250000 = 250000
    CAN_500000 = 500000
    CAN_33333 = 33333
    CAN_83333 = 83333
    ISO15765_125000 = 125000
    ISO15765_250000 = 250000
    ISO15765_500000 = 500000
    GMUART_8192 = 8192
    GMUART_160 = 160

TxFlag

Transmission flags for PassThruMsg.

class TxFlag(Flag):
    NONE = 0x00000000
    SCI_TX_VOLTAGE = 0x00800000       # SCI high voltage (12V)
    SCI_MODE = 0x00400000             # SCI mode
    WAIT_P3_MIN_ONLY = 0x00000200     # Wait P3_MIN only
    CAN_29BIT_ID = 0x00000100         # Use 29-bit CAN identifier
    ISO15765_ADDR_TYPE = 0x00000080   # ISO15765 addressing type
    ISO15765_FRAME_PAD = 0x00000040   # Pad ISO15765 frame
    SW_CAN_HV_TX = 0x00000400         # SW-CAN high voltage TX

RxStatus

Reception status flags for PassThruMsg.

class RxStatus(Flag):
    NONE = 0x00000000
    TX_MSG_TYPE = 0x00000001          # Message is from TX
    START_OF_MESSAGE = 0x00000002     # First message
    RX_BREAK = 0x00000004             # Break received
    TX_INDICATION_SUCCESS = 0x00000008 # TX successful
    ISO15765_PADDING_ERROR = 0x00000010 # Padding error
    ERROR_INDICATION = 0x20           # Error occurred
    BUFFER_OVERFLOW = 0x40            # Buffer overflow
    ISO15765_ADDR_TYPE = 0x00000080   # ISO15765 addressing
    CAN_29BIT_ID = 0x00000100         # 29-bit CAN ID
    TX_FAILED = 0x200                 # TX failed
    SW_CAN_HV_TX = 0x00000400         # SW-CAN HV TX
    SW_CAN_NS_RX = 0x00040000         # SW-CAN normal speed RX
    SW_CAN_HS_RX = 0x00020000         # SW-CAN high speed RX
    SW_CAN_HV_RX = 0x00010000         # SW-CAN high voltage RX

ConnectFlag

Connection flags for PassThruConnect.

class ConnectFlag(Flag):
    NONE = 0x0000
    ISO9141_K_LINE_ONLY = 0x1000      # Use K-line only (no L-line)
    CAN_ID_BOTH = 0x0800              # 11-bit and 29-bit CAN
    ISO9141_NO_CHECKSUM = 0x0200      # No checksum
    CAN_29BIT_ID = 0x0100             # Use 29-bit CAN IDs
    FULL_DUPLEX = 0x1                 # Full duplex mode

ConfigParameter

Configuration parameters for GetConfig/SetConfig.

class ConfigParameter(IntEnum):
    DATA_RATE = 0x01                  # Baud rate value
    LOOPBACK = 0x03                   # Loopback mode (0=off, 1=on)
    NODE_ADDRESS = 0x04               # Node address for J1850
    NETWORK_LINE = 0x05               # Network line (0=BUS_NORMAL, 1=BUS_PLUS, 2=BUS_MINUS)
    P1_MIN = 0x06                     # ISO 9141 P1 min timing
    P1_MAX = 0x07                     # ISO 9141 P1 max timing
    P2_MIN = 0x08                     # ISO 9141 P2 min timing
    P2_MAX = 0x09                     # ISO 9141 P2 max timing
    P3_MIN = 0x0A                     # ISO 9141 P3 min timing
    P3_MAX = 0x0B                     # ISO 9141 P3 max timing
    P4_MIN = 0x0C                     # ISO 9141 P4 min timing
    P4_MAX = 0x0D                     # ISO 9141 P4 max timing
    W1 = 0x0E                         # ISO 9141 W1 timing
    W2 = 0x0F                         # ISO 9141 W2 timing
    W3 = 0x10                         # ISO 9141 W3 timing
    W4 = 0x11                         # ISO 9141 W4 timing
    W5 = 0x12                         # ISO 9141 W5 timing
    TIDLE = 0x13                      # Bus idle time
    TINIL = 0x14                      # Initialization time
    TWUP = 0x15                       # Wakeup time
    PARITY = 0x16                     # Parity (0=no parity, 1=odd, 2=even)
    BIT_SAMPLE_POINT = 0x17           # CAN bit sample point (%)
    SYNC_JUMP_WIDTH = 0x18            # CAN sync jump width
    # ISO15765 parameters
    ISO15765_BS = 0x1E                # Block size
    ISO15765_STMIN = 0x1F             # Separation time minimum
    ISO15765_WFT_MAX = 0x25           # Wait frame transmit maximum
    ISO15765_PAD_VALUE = 0X2B         # Padding value
    # ... many more parameters available

Structures

PassThruMsg

Main message structure for J2534 communication.

class PassThruMsg(Structure):
    _fields_ = [
        ("ProtocolID", c_int),         # Protocol identifier
        ("RxStatus", c_uint),          # Reception status flags
        ("TxFlags", c_uint),           # Transmission flags
        ("Timestamp", c_uint),         # Message timestamp (microseconds)
        ("DataSize", c_uint),          # Number of data bytes
        ("ExtraDataIndex", c_uint),    # Start of extra data
        ("Data", c_byte * 4128)        # Message data (max 4128 bytes)
    ]
    
    def __init__(self, myProtocolId: ProtocolID = None, 
                 myTxFlag: TxFlag = None, 
                 myByteArray: bytes = None)
    
    def SetBytes(self, myByteArray: bytes)
    def GetBytes(self) -> bytes
    def ToString(self, tab: str) -> str

Usage Example:

# Create a CAN message
msg = PassThruMsg(
    ProtocolID.CAN,
    TxFlag.CAN_29BIT_ID,
    bytes([0x18, 0xDA, 0xF1, 0x10, 0x02, 0x01, 0x00])
)

# Access message properties
print(f"Protocol: {msg.ProtocolID}")
print(f"Data Size: {msg.DataSize}")
print(f"Data: {msg.GetBytes().hex()}")

# Modify message data
msg.SetBytes(bytes([0x18, 0xDA, 0xF1, 0x10, 0x02, 0x01, 0x01]))

SConfig

Configuration parameter structure.

class SConfig(Structure):
    _fields_ = [
        ("Parameter", c_int),          # ConfigParameter enum value
        ("Value", c_uint16)            # Parameter value
    ]

Usage Example:

# Create configuration
config = SConfig()
config.Parameter = ConfigParameter.DATA_RATE
config.Value = 500000

# Or use constructor
config = SConfig(ConfigParameter.LOOPBACK, 1)

SByteArray

Byte array structure for IOCTL operations.

class SByteArray(Structure):
    _fields_ = [
        ("NumOfBytes", c_int),         # Number of bytes
        ("BytePtr", c_void_p)          # Pointer to byte array
    ]

Utilities

Utils Class

Helper methods for working with J2534 structures.

class Utils:
    @staticmethod
    def AsString(ptr: c_void_p) -> str
        """Convert IntPtr to string"""
    
    @staticmethod
    def ToIntPtr(msg: PassThruMsg) -> c_void_p
        """Convert PassThruMsg to IntPtr"""
    
    @staticmethod
    def AsMsgList(ptr: c_void_p, count: int) -> List[PassThruMsg]
        """Convert IntPtr to PassThruMsg list"""
    
    @staticmethod
    def AsList(ptr: c_void_p, count: int, struct_type: type) -> List
        """Convert IntPtr to list of structures"""
    
    @staticmethod
    def AsStruct(ptr: c_void_p, struct_type: type)
        """Convert IntPtr to structure"""
    
    @staticmethod
    def AsNullableStruct(ptr: c_void_p, struct_type: type) -> Optional
        """Convert IntPtr to nullable structure"""

Usage Examples

Example 1: Read VIN from Vehicle

from J2534 import *

def read_vin():
    # Setup
    device = J2534Device()
    device.FunctionLibrary = "C:\\Program Files\\...\\J2534.dll"
    
    j2534 = J2534Functions()
    
    if not j2534.LoadLibrary(device):
        print("Failed to load library")
        return
    
    # Open device
    deviceId = c_uint(0)
    result = j2534.PassThruOpen(c_void_p(0), deviceId)
    if result != J2534Err.STATUS_NOERROR:
        print(f"Failed to open device: {result}")
        return
    
    # Connect to ISO15765 (CAN)
    channelId = c_uint(0)
    result = j2534.PassThruConnect(
        deviceId.value,
        ProtocolID.ISO15765,
        ConnectFlag.NONE,
        BaudRate.ISO15765_500000,
        channelId
    )
    
    if result != J2534Err.STATUS_NOERROR:
        print(f"Failed to connect: {result}")
        j2534.PassThruClose(deviceId.value)
        return
    
    try:
        # Set up flow control filter (required for ISO15765)
        maskMsg = PassThruMsg(ProtocolID.ISO15765, TxFlag.NONE, 
                             bytes([0x00, 0x00, 0x00, 0x00]))
        patternMsg = PassThruMsg(ProtocolID.ISO15765, TxFlag.NONE,
                                bytes([0x00, 0x00, 0x07, 0xE8]))
        flowMsg = PassThruMsg(ProtocolID.ISO15765, TxFlag.NONE,
                             bytes([0x00, 0x00, 0x07, 0xE0]))
        
        filterId = c_int(0)
        result = j2534.PassThruStartMsgFilter(
            channelId.value,
            FilterType.FLOW_CONTROL_FILTER,
            Utils.ToIntPtr(maskMsg),
            Utils.ToIntPtr(patternMsg),
            Utils.ToIntPtr(flowMsg),
            filterId
        )
        
        if result != J2534Err.STATUS_NOERROR:
            print(f"Failed to start filter: {result}")
            return
        
        # Send VIN request (Service 09, PID 02)
        vinRequest = PassThruMsg(
            ProtocolID.ISO15765,
            TxFlag.NONE,
            bytes([0x00, 0x00, 0x07, 0xDF, 0x09, 0x02])
        )
        
        txMsgPtr = Utils.ToIntPtr(vinRequest)
        numMsgs = c_int(1)
        result = j2534.PassThruWriteMsgs(
            channelId.value,
            txMsgPtr,
            numMsgs,
            1000
        )
        
        if result != J2534Err.STATUS_NOERROR:
            print(f"Failed to send request: {result}")
            return
        
        # Read response
        numMsgs = c_int(10)
        rxMsgs = cast(create_string_buffer(sizeof(PassThruMsg) * numMsgs.value), c_void_p)
        result = j2534.PassThruReadMsgs(
            channelId.value,
            rxMsgs,
            numMsgs,
            2000
        )
        
        if result == J2534Err.STATUS_NOERROR:
            messages = Utils.AsMsgList(rxMsgs, numMsgs.value)
            for msg in messages:
                data = msg.GetBytes()
                # Skip addressing bytes, extract VIN
                if len(data) > 5 and data[4] == 0x49 and data[5] == 0x02:
                    vin_bytes = data[6:]
                    vin = vin_bytes.decode('ascii', errors='ignore')
                    print(f"VIN: {vin}")
        
        # Cleanup filter
        j2534.PassThruStopMsgFilter(channelId.value, filterId.value)
        
    finally:
        # Disconnect and close
        j2534.PassThruDisconnect(channelId.value)
        j2534.PassThruClose(deviceId.value)
        j2534.FreeLibrary()

if __name__ == "__main__":
    read_vin()

Example 2: Monitor CAN Bus

from J2534 import *
import time

def monitor_can_bus(duration_seconds=10):
    device = J2534Device()
    device.FunctionLibrary = "C:\\Path\\To\\J2534.dll"
    
    j2534_ext = J2534FunctionsExtended()
    
    if not j2534_ext.LoadLibrary(device):
        print("Failed to load library")
        return
    
    deviceId = c_uint(0)
    result = j2534_ext.PassThruOpen(c_void_p(0), deviceId)
    if result != J2534Err.STATUS_NOERROR:
        print(f"Failed to open: {result}")
        return
    
    # Connect in passive mode (sniff mode)
    channelId = c_uint(0)
    result = j2534_ext.PassThruConnect(
        deviceId.value,
        ProtocolID.CAN,
        ConnectFlag.NONE,  # Passive listening
        BaudRate.CAN_500000,
        channelId
    )
    
    if result != J2534Err.STATUS_NOERROR:
        print(f"Failed to connect: {result}")
        j2534_ext.PassThruClose(deviceId.value)
        return
    
    try:
        # Set up pass-all filter to receive everything
        maskMsg = PassThruMsg(ProtocolID.CAN, TxFlag.NONE,
                             bytes([0x00, 0x00, 0x00, 0x00]))
        patternMsg = PassThruMsg(ProtocolID.CAN, TxFlag.NONE,
                                bytes([0x00, 0x00, 0x00, 0x00]))
        
        filterId = c_int(0)
        result = j2534_ext.PassThruStartMsgFilter(
            channelId.value,
            FilterType.PASS_FILTER,
            Utils.ToIntPtr(maskMsg),
            Utils.ToIntPtr(patternMsg),
            c_void_p(0),
            filterId
        )
        
        print(f"Monitoring CAN bus for {duration_seconds} seconds...")
        print("CAN ID       Data")
        print("-" * 50)
        
        start_time = time.time()
        message_count = 0
        
        while time.time() - start_time < duration_seconds:
            messages = []
            result = j2534_ext.ReadAllMessages(
                channelId.value,
                50,  # Read up to 50 messages
                100,  # 100ms timeout
                messages,
                readUntilTimeout=False  # Single batch
            )
            
            for msg in messages:
                data = msg.GetBytes()
                can_id = int.from_bytes(data[0:4], 'big') & 0x1FFFFFFF
                payload = data[4:]
                print(f"0x{can_id:08X}   {payload.hex().upper()}")
                message_count += 1
        
        print(f"\nReceived {message_count} messages")
        
        j2534_ext.PassThruStopMsgFilter(channelId.value, filterId.value)
        
    finally:
        j2534_ext.PassThruDisconnect(channelId.value)
        j2534_ext.PassThruClose(deviceId.value)
        j2534_ext.FreeLibrary()

if __name__ == "__main__":
    monitor_can_bus(duration_seconds=30)

Example 3: Read Diagnostic Trouble Codes (DTCs)

from J2534 import *

def read_dtcs():
    """Read DTCs using UDS (ISO 14229) over ISO15765"""
    device = J2534Device()
    device.FunctionLibrary = "C:\\Path\\To\\J2534.dll"
    
    j2534 = J2534Functions()
    
    if not j2534.LoadLibrary(device):
        print("Failed to load library")
        return
    
    deviceId = c_uint(0)
    result = j2534.PassThruOpen(c_void_p(0), deviceId)
    if result != J2534Err.STATUS_NOERROR:
        return
    
    channelId = c_uint(0)
    result = j2534.PassThruConnect(
        deviceId.value,
        ProtocolID.ISO15765,
        ConnectFlag.NONE,
        BaudRate.ISO15765_500000,
        channelId
    )
    
    if result != J2534Err.STATUS_NOERROR:
        j2534.PassThruClose(deviceId.value)
        return
    
    try:
        # Set up filter
        maskMsg = PassThruMsg(ProtocolID.ISO15765, TxFlag.NONE,
                             bytes([0x00, 0x00, 0x00, 0x00]))
        patternMsg = PassThruMsg(ProtocolID.ISO15765, TxFlag.NONE,
                                bytes([0x00, 0x00, 0x07, 0xE8]))
        flowMsg = PassThruMsg(ProtocolID.ISO15765, TxFlag.NONE,
                             bytes([0x00, 0x00, 0x07, 0xE0]))
        
        filterId = c_int(0)
        j2534.PassThruStartMsgFilter(
            channelId.value,
            FilterType.FLOW_CONTROL_FILTER,
            Utils.ToIntPtr(maskMsg),
            Utils.ToIntPtr(patternMsg),
            Utils.ToIntPtr(flowMsg),
            filterId
        )
        
        # Send Read DTC request (Service 0x19, Sub-function 0x02)
        dtcRequest = PassThruMsg(
            ProtocolID.ISO15765,
            TxFlag.NONE,
            bytes([0x00, 0x00, 0x07, 0xE0, 0x19, 0x02, 0x0F])  # Read DTCs by status mask
        )
        
        txMsgPtr = Utils.ToIntPtr(dtcRequest)
        numMsgs = c_int(1)
        j2534.PassThruWriteMsgs(channelId.value, txMsgPtr, numMsgs, 1000)
        
        # Read response
        numMsgs = c_int(20)
        rxMsgs = cast(create_string_buffer(sizeof(PassThruMsg) * numMsgs.value), c_void_p)
        result = j2534.PassThruReadMsgs(channelId.value, rxMsgs, numMsgs, 2000)
        
        if result == J2534Err.STATUS_NOERROR:
            messages = Utils.AsMsgList(rxMsgs, numMsgs.value)
            
            for msg in messages:
                data = msg.GetBytes()
                # Parse DTC response (0x59 is positive response to 0x19)
                if len(data) > 5 and data[4] == 0x59 and data[5] == 0x02:
                    dtc_count = data[6]
                    print(f"Found {dtc_count} DTCs:")
                    
                    # Parse DTCs (3 bytes each)
                    idx = 7
                    for i in range(dtc_count):
                        if idx + 2 < len(data):
                            dtc = (data[idx] << 16) | (data[idx+1] << 8) | data[idx+2]
                            
                            # Convert to standard DTC format (P0xxx, C0xxx, etc.)
                            first_char = ['P', 'C', 'B', 'U'][(dtc >> 14) & 0x3]
                            second_digit = (dtc >> 12) & 0x3
                            remaining = dtc & 0xFFF
                            
                            dtc_string = f"{first_char}{second_digit}{remaining:03X}"
                            print(f"  DTC: {dtc_string}")
                            
                            idx += 3
        
        j2534.PassThruStopMsgFilter(channelId.value, filterId.value)
        
    finally:
        j2534.PassThruDisconnect(channelId.value)
        j2534.PassThruClose(deviceId.value)
        j2534.FreeLibrary()

if __name__ == "__main__":
    read_dtcs()

Example 4: Clear DTCs

from J2534 import *

def clear_dtcs():
    """Clear DTCs using UDS service 0x14"""
    device = J2534Device()
    device.FunctionLibrary = "C:\\Path\\To\\J2534.dll"
    
    j2534 = J2534Functions()
    
    if not j2534.LoadLibrary(device):
        print("Failed to load library")
        return False
    
    deviceId = c_uint(0)
    j2534.PassThruOpen(c_void_p(0), deviceId)
    
    channelId = c_uint(0)
    j2534.PassThruConnect(
        deviceId.value,
        ProtocolID.ISO15765,
        ConnectFlag.NONE,
        BaudRate.ISO15765_500000,
        channelId
    )
    
    try:
        # Set up filter
        maskMsg = PassThruMsg(ProtocolID.ISO15765, TxFlag.NONE,
                             bytes([0x00, 0x00, 0x00, 0x00]))
        patternMsg = PassThruMsg(ProtocolID.ISO15765, TxFlag.NONE,
                                bytes([0x00, 0x00, 0x07, 0xE8]))
        flowMsg = PassThruMsg(ProtocolID.ISO15765, TxFlag.NONE,
                             bytes([0x00, 0x00, 0x07, 0xE0]))
        
        filterId = c_int(0)
        j2534.PassThruStartMsgFilter(
            channelId.value,
            FilterType.FLOW_CONTROL_FILTER,
            Utils.ToIntPtr(maskMsg),
            Utils.ToIntPtr(patternMsg),
            Utils.ToIntPtr(flowMsg),
            filterId
        )
        
        # Send Clear DTC request (Service 0x14)
        clearRequest = PassThruMsg(
            ProtocolID.ISO15765,
            TxFlag.NONE,
            bytes([0x00, 0x00, 0x07, 0xE0, 0x14, 0xFF, 0xFF, 0xFF])
        )
        
        txMsgPtr = Utils.ToIntPtr(clearRequest)
        numMsgs = c_int(1)
        result = j2534.PassThruWriteMsgs(channelId.value, txMsgPtr, numMsgs, 1000)
        
        if result != J2534Err.STATUS_NOERROR:
            print(f"Failed to send clear command: {result}")
            return False
        
        # Read response
        numMsgs = c_int(5)
        rxMsgs = cast(create_string_buffer(sizeof(PassThruMsg) * numMsgs.value), c_void_p)
        result = j2534.PassThruReadMsgs(channelId.value, rxMsgs, numMsgs, 2000)
        
        if result == J2534Err.STATUS_NOERROR:
            messages = Utils.AsMsgList(rxMsgs, numMsgs.value)
            
            for msg in messages:
                data = msg.GetBytes()
                # 0x54 is positive response to 0x14
                if len(data) > 4 and data[4] == 0x54:
                    print("DTCs cleared successfully!")
                    return True
                elif len(data) > 4 and data[4] == 0x7F:
                    # Negative response
                    nrc = data[6] if len(data) > 6 else 0
                    print(f"Failed to clear DTCs. Negative response code: 0x{nrc:02X}")
                    return False
        
        print("No response received")
        return False
        
    finally:
        j2534.PassThruStopMsgFilter(channelId.value, filterId.value)
        j2534.PassThruDisconnect(channelId.value)
        j2534.PassThruClose(deviceId.value)
        j2534.FreeLibrary()

if __name__ == "__main__":
    clear_dtcs()

Example 5: Battery Voltage Monitor

from J2534 import *
import time

def monitor_battery_voltage(duration_seconds=60):
    """Monitor battery voltage over time"""
    device = J2534Device()
    device.FunctionLibrary = "C:\\Path\\To\\J2534.dll"
    
    j2534_ext = J2534FunctionsExtended()
    
    if not j2534_ext.LoadLibrary(device):
        print("Failed to load library")
        return
    
    deviceId = c_uint(0)
    result = j2534_ext.PassThruOpen(c_void_p(0), deviceId)
    if result != J2534Err.STATUS_NOERROR:
        print(f"Failed to open: {result}")
        return
    
    try:
        print(f"Monitoring battery voltage for {duration_seconds} seconds...")
        print("Time (s)    Voltage (V)")
        print("-" * 30)
        
        start_time = time.time()
        
        while time.time() - start_time < duration_seconds:
            voltage = c_int(0)
            result = j2534_ext.ReadBatteryVoltage(deviceId.value, voltage)
            
            if result == J2534Err.STATUS_NOERROR:
                voltage_v = voltage.value / 1000.0
                elapsed = time.time() - start_time
                print(f"{elapsed:6.1f}      {voltage_v:5.2f}")
            else:
                print(f"Error reading voltage: {result}")
            
            time.sleep(1.0)  # Read every second
    
    finally:
        j2534_ext.PassThruClose(deviceId.value)
        j2534_ext.FreeLibrary()

if __name__ == "__main__":
    monitor_battery_voltage(duration_seconds=30)

Error Handling

Using J2534Exception

from J2534 import *

def safe_operation():
    j2534 = J2534Functions()
    device = J2534Device()
    device.FunctionLibrary = "C:\\Path\\To\\J2534.dll"
    
    try:
        if not j2534.LoadLibrary(device):
            raise J2534Exception(J2534Err.ERR_DLL_NOT_LOADED)
        
        deviceId = c_uint(0)
        result = j2534.PassThruOpen(c_void_p(0), deviceId)
        
        if result != J2534Err.STATUS_NOERROR:
            raise J2534Exception(result)
        
        # ... perform operations ...
        
    except J2534Exception as e:
        print(f"J2534 Error: {e.Error.name} (0x{e.Error.value:02X})")
        print(f"Description: {e}")
    
    finally:
        if j2534.IsDLLLoaded:
            j2534.FreeLibrary()

Error Code Handling

def handle_j2534_error(error_code: J2534Err):
    """Handle different J2534 errors"""
    error_messages = {
        J2534Err.ERR_TIMEOUT: "Operation timed out",
        J2534Err.ERR_BUFFER_EMPTY: "No messages available",
        J2534Err.ERR_BUFFER_FULL: "Buffer is full, cannot send more messages",
        J2534Err.ERR_INVALID_CHANNEL_ID: "Invalid channel ID specified",
        J2534Err.ERR_ConnectedDevice_NOT_CONNECTED: "Device is not connected",
        J2534Err.ERR_FAILED: "General failure occurred"
    }
    
    message = error_messages.get(error_code, f"Unknown error: {error_code}")
    print(f"Error: {message}")
    
    return error_code != J2534Err.STATUS_NOERROR

# Usage
result = j2534.PassThruReadMsgs(channelId.value, rxMsgs, numMsgs, timeout)
if handle_j2534_error(result):
    # Handle error
    pass

Troubleshooting

Common Issues and Solutions

1. Library Fails to Load

Problem: LoadLibrary() returns False

Solutions:

  • Verify the DLL path is correct and the file exists
  • Check that the DLL is the correct architecture (32-bit vs 64-bit)
  • Ensure Python architecture matches DLL architecture
  • Verify all DLL dependencies are installed
  • Try running as Administrator
import os

dll_path = "C:\\Path\\To\\J2534.dll"
if not os.path.exists(dll_path):
    print(f"DLL not found: {dll_path}")
else:
    print(f"DLL exists: {dll_path}")

2. ERR_DEVICE_NOT_CONNECTED

Problem: Device not physically connected or drivers not installed

Solutions:

  • Check physical connection
  • Verify device drivers are installed
  • Try a different USB port
  • Check Device Manager for any issues
  • Restart the device

3. ERR_TIMEOUT on Read

Problem: No response from vehicle

Solutions:

  • Increase timeout value
  • Verify vehicle is powered on (ignition on)
  • Check physical connections (OBD-II cable)
  • Verify correct protocol and baud rate
  • Ensure message filters are set up correctly
# Increase timeout
result = j2534.PassThruReadMsgs(
    channelId.value,
    rxMsgs,
    numMsgs,
    5000  # 5 second timeout instead of 1 second
)

4. ERR_INVALID_MSG

Problem: Message format is incorrect

Solutions:

  • Verify message data length
  • Check protocol-specific requirements
  • Ensure CAN ID format is correct (11-bit vs 29-bit)
  • Verify addressing bytes for ISO15765
# For ISO15765, first 4 bytes are CAN ID
# Byte 0-3: CAN ID (big-endian)
# Byte 4+: UDS/OBD data

msg = PassThruMsg(
    ProtocolID.ISO15765,
    TxFlag.NONE,
    bytes([0x00, 0x00, 0x07, 0xE0,  # CAN ID 0x7E0
           0x01, 0x00])               # Service 0x01, PID 0x00
)

5. Memory Access Violations

Problem: Application crashes or ERR_ACCESS_VIOLATION

Solutions:

  • Ensure proper use of ctypes
  • Don't free memory managed by the library
  • Use byref() for references
  • Verify structure sizes match
# Correct usage with byref
deviceId = c_uint(0)
result = j2534.PassThruOpen(c_void_p(0), deviceId)  # WRONG - missing byref
result = j2534.PassThruOpen(c_void_p(0), byref(deviceId))  # WRONG - actually this is handled internally

# The library handles byref internally in most cases
# Just pass the c_uint directly
deviceId = c_uint(0)
result = j2534.PassThruOpen(c_void_p(0), deviceId)

Debug Mode

Enable verbose logging for debugging:

import logging

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

def debug_j2534_call(function_name, result):
    if result == J2534Err.STATUS_NOERROR:
        logger.debug(f"{function_name}: SUCCESS")
    else:
        logger.error(f"{function_name}: ERROR - {result.name} (0x{result.value:02X})")

# Usage
result = j2534.PassThruConnect(deviceId.value, protocol, flags, baud, channelId)
debug_j2534_call("PassThruConnect", result)

Advanced Topics

Multi-Channel Operation

# Open multiple channels for different protocols
can_channel = c_uint(0)
iso9141_channel = c_uint(0)

# Connect to CAN
j2534.PassThruConnect(
    deviceId.value,
    ProtocolID.CAN,
    ConnectFlag.NONE,
    BaudRate.CAN_500000,
    can_channel
)

# Connect to ISO9141
j2534.PassThruConnect(
    deviceId.value,
    ProtocolID.ISO9141,
    ConnectFlag.NONE,
    BaudRate.ISO9141_10400,
    iso9141_channel
)

# Use both channels...

# Disconnect both
j2534.PassThruDisconnect(can_channel.value)
j2534.PassThruDisconnect(iso9141_channel.value)

Periodic Messages (Tester Present)

# Send periodic keep-alive message
tester_present = PassThruMsg(
    ProtocolID.ISO15765,
    TxFlag.NONE,
    bytes([0x00, 0x00, 0x07, 0xE0, 0x3E, 0x00])  # Tester Present
)

msgId = c_int(0)
timeInterval = 2000  # Every 2 seconds

result = j2534.PassThruStartPeriodicMsg(
    channelId.value,
    Utils.ToIntPtr(tester_present),
    msgId,
    timeInterval
)

# Later, stop the periodic message
j2534.PassThruStopPeriodicMsg(channelId.value, msgId.value)

Message Filtering

# Block specific CAN IDs
blockMask = PassThruMsg(ProtocolID.CAN, TxFlag.NONE,
                       bytes([0xFF, 0xFF, 0xFF, 0xFF]))  # Check all bits
blockPattern = PassThruMsg(ProtocolID.CAN, TxFlag.NONE,
                          bytes([0x00, 0x00, 0x05, 0x00]))  # Block ID 0x500

filterId = c_int(0)
j2534.PassThruStartMsgFilter(
    channelId.value,
    FilterType.BLOCK_FILTER,
    Utils.ToIntPtr(blockMask),
    Utils.ToIntPtr(blockPattern),
    c_void_p(0),
    filterId
)

# Pass specific range of IDs
passMask = PassThruMsg(ProtocolID.CAN, TxFlag.NONE,
                      bytes([0xFF, 0xFF, 0xF0, 0x00]))  # Check upper bits
passPattern = PassThruMsg(ProtocolID.CAN, TxFlag.NONE,
                         bytes([0x00, 0x00, 0x70, 0x00]))  # Pass 0x700-0x7FF

filterId2 = c_int(0)
j2534.PassThruStartMsgFilter(
    channelId.value,
    FilterType.PASS_FILTER,
    Utils.ToIntPtr(passMask),
    Utils.ToIntPtr(passPattern),
    c_void_p(0),
    filterId2
)

Configuration Management

from J2534 import *

def configure_channel(j2534_ext, channelId):
    """Configure channel parameters"""
    
    # Get current configuration
    config_get = [
        SConfig(ConfigParameter.DATA_RATE, 0),
        SConfig(ConfigParameter.LOOPBACK, 0)
    ]
    
    result = j2534_ext.GetConfig(channelId, config_get)
    if result == J2534Err.STATUS_NOERROR:
        print(f"Current baud rate: {config_get[0].Value}")
        print(f"Loopback: {config_get[1].Value}")
    
    # Set new configuration
    config_set = [
        SConfig(ConfigParameter.LOOPBACK, 0),  # Disable loopback
        SConfig(ConfigParameter.ISO15765_BS, 8),  # Block size
        SConfig(ConfigParameter.ISO15765_STMIN, 10)  # 10ms separation time
    ]
    
    result = j2534_ext.SetConfig(channelId, config_set)
    if result == J2534Err.STATUS_NOERROR:
        print("Configuration updated successfully")
    else:
        print(f"Failed to set configuration: {result}")

Programming Voltage Control

# Set programming voltage (for ECU flashing)
result = j2534.PassThruSetProgrammingVoltage(
    deviceId.value,
    PinNumber.PIN_6,
    PinVoltage.FEPS_VOLTAGE  # 18V
)

if result == J2534Err.STATUS_NOERROR:
    print("Programming voltage set to 18V on Pin 6")
    
    # Perform programming operations...
    
    # Turn off programming voltage
    j2534.PassThruSetProgrammingVoltage(
        deviceId.value,
        PinNumber.PIN_6,
        PinVoltage.VOLTAGE_OFF
    )

Reading Device Information

def get_device_version(j2534, deviceId):
    """Read device firmware and API versions"""
    firmware = create_string_buffer(80)
    dll_version = create_string_buffer(80)
    api_version = create_string_buffer(80)
    
    result = j2534.PassThruReadVersion(
        deviceId.value,
        cast(firmware, c_void_p),
        cast(dll_version, c_void_p),
        cast(api_version, c_void_p)
    )
    
    if result == J2534Err.STATUS_NOERROR:
        print(f"Firmware: {firmware.value.decode('ascii', errors='ignore')}")
        print(f"DLL Version: {dll_version.value.decode('ascii', errors='ignore')}")
        print(f"API Version: {api_version.value.decode('ascii', errors='ignore')}")

Best Practices

  1. Always Check Return Values: Every J2534 function returns a status code. Always check it.

  2. Proper Resource Management: Use try-finally blocks to ensure resources are cleaned up.

  3. Timeouts: Set appropriate timeouts based on expected response times.

  4. Message Filtering: Set up proper filters before reading messages to avoid buffer overflow.

  5. Error Handling: Implement robust error handling for production code.

  6. Testing: Test thoroughly with your specific hardware before deployment.

  7. Documentation: Keep SAE J2534 specification handy for reference.

Contributing

Contributions are welcome! Please ensure:

  • Exact naming conventions are maintained (for C# compatibility)
  • All changes are tested with real J2534 hardware
  • Documentation is updated for new features
  • Error handling is robust

Support

For issues specific to this Python implementation, please check:

  1. This README for solutions
  2. The SAE J2534 specification
  3. Your J2534 device manufacturer's documentation

Changelog

Version 1.0.0 (Initial Release)

  • Complete Python port from C#
  • All J2534 v04.04 functions implemented
  • Extended functions for battery voltage, buffer management
  • Full support for all protocols
  • Comprehensive error handling
  • Utility classes for common operations

Note: This library requires a physical J2534-compliant PassThru device and its associated drivers to function. It is intended for automotive diagnostics and ECU programming professionals.

About

In 32 bit Python.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages