Quantex GmbH
您的地区:欧洲

PassThruIoctl v4.04 v5.0

输入/输出管理

最后修改:

说明

设备与通道的通用管理函数。根据参数 IoctlID 执行不同的操作:读取/写入配置、初始化协议、清空缓冲区以及其他辅助操作。

long PassThruIoctl(unsigned long ChannelID, unsigned long IoctlID, void *pInput, void *pOutput)

参数

IoctlID 说明
GET_CONFIG 0x01 读取协议参数
SET_CONFIG 0x02 写入协议参数
READ_VBATT 0x03 读取供电电压
FIVE_BAUD_INIT 0x04 K-Line 5 波特初始化
FAST_INIT 0x05 K-Line Fast 初始化
CLEAR_TX_BUFFER 0x07 清空发送队列
CLEAR_RX_BUFFER 0x08 清空接收队列
CLEAR_PERIODIC_MSGS 0x09 清除周期性消息
CLEAR_MSG_FILTERS 0x0A 清除所有过滤器
CLEAR_FUNCT_MSG_LOOKUP_TABLE 0x0B 清除功能寻址表
ADD_TO_FUNCT_MSG_LOOKUP_TABLE 0x0C 向功能寻址表添加
DELETE_FROM_FUNCT_MSG_LOOKUP_TABLE 0x0D 从功能寻址表删除
READ_PROG_VOLTAGE 0x0E 读取编程电压
SW_CAN_HS 0x8000 将 SW-CAN 切换至高速模式
SW_CAN_NS 0x8001 将 SW-CAN 切换至正常模式
BUS_ON v5.0 0x0F 将 CAN 控制器连接到总线
REQUEST_CONNECTION J2534-2 0x800A 建立 TP 2.0 连接
TEARDOWN_CONNECTION J2534-2 0x800B 断开 TP 2.0 连接
GET_DEVICE_INFO J2534-2 0x800C 获取设备信息
GET_PROTOCOL_INFO J2534-2 0x800D 获取协议信息
ISO13400_PS Quantex 0x8110-0x8113 DoIP(Diagnostics over IP)命令

返回的错误代码

代码 说明 可能原因与解决方法
STATUS_NOERROR 函数执行成功
ERR_DEVICE_NOT_CONNECTED 与适配器无连接
  • 适配器已关闭或不在可访问范围内
  • 解决方法:检查适配器供电与网络连接
ERR_INVALID_CHANNEL_ID 无效的通道标识符
  • ChannelID 未通过 PassThruConnect 获取,或通道已关闭
  • 解决方法:确认 PassThruConnect 已成功执行
ERR_INVALID_IOCTL_ID 无效的 IoctlID 标识符
  • 指定的 IoctlID 不受支持
  • 解决方法:检查 IoctlID 取值是否正确
ERR_NULL_PARAMETER 必填指针处传入了 NULL
  • 需要指针时 pInput 或 pOutput 为 NULL
  • 解决方法:传入正确的指针
ERR_NOT_SUPPORTED 操作不受支持
  • 适配器不支持所请求的操作
  • 解决方法:通过 GET_DEVICE_INFO 检查适配器的功能
ERR_INVALID_IOCTL_VALUE 参数值非法
  • pInput 中的值超出允许范围
  • 解决方法:检查取值的允许范围
ERR_INVALID_MSG 消息结构不正确
  • FAST_INIT 的 pInput 中结构有误
  • 解决方法:检查 PASSTHRU_MSG 各字段是否正确
ERR_FAILED 未定义的错误
  • 库或适配器的内部错误
  • 解决方法:调用 PassThruGetLastError() 获取错误描述

READ_VBATT — 读取供电电压

返回 OBD-II 接口(第 16 脚)上的电压。数值以毫伏为单位,除以 1000 即可得到伏特值。该命令无需打开通道,可在 PassThruOpen 之后立即执行。

pInput NULL
pOutput unsigned long* — 电压,单位 mV

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long DeviceID;  // 由 PassThruOpen 返回
unsigned long voltage;
long ret;

ret = PassThruIoctl(DeviceID, READ_VBATT, NULL, &voltage);
if (ret == STATUS_NOERROR)
{
    printf("电压: %.2f V\n", voltage / 1000.0);
}

Kotlin (Android) 示例

// deviceID 此前由 ptOpen 返回
val result = j2534.ptIoctl(deviceID, READ_VBATT, 0, null)
if (result.status == STATUS_NOERROR) {
    val voltageV = result.outputValue / 1000.0
    Log.i("J2534", "电压: ${"%.2f".format(voltageV)} V")
}

Python 示例

from ctypes import *

voltage = c_ulong()
ret = j2534.PassThruIoctl(device_id, READ_VBATT, None, byref(voltage))
if ret == 0:  # STATUS_NOERROR
    print(f"电压: {voltage.value / 1000:.2f} V")

C# 示例

uint voltage;
int ret = J2534.PassThruIoctl(deviceId, READ_VBATT, IntPtr.Zero, out voltage);
if (ret == 0)
{
    Console.WriteLine($"电压: {voltage / 1000.0:F2} V");
}

READ_PROG_VOLTAGE — 读取编程电压

返回编程输出端当前的电压。数值以毫伏为单位,四舍五入到最接近的十分之一伏。

pInput NULL
pOutput unsigned long* — 电压,单位 mV

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long DeviceID;
unsigned long voltage;
long ret;

ret = PassThruIoctl(DeviceID, READ_PROG_VOLTAGE, NULL, &voltage);
if (ret == STATUS_NOERROR)
{
    printf("编程电压: %.2f V\n", voltage / 1000.0);
}

Kotlin (Android) 示例

val result = j2534.ptIoctl(deviceID, READ_PROG_VOLTAGE, 0, null)
if (result.status == STATUS_NOERROR) {
    val voltageV = result.outputValue / 1000.0
    Log.i("J2534", "编程电压: ${"%.2f".format(voltageV)} V")
}

Python 示例

from ctypes import *

voltage = c_ulong()
ret = j2534.PassThruIoctl(device_id, READ_PROG_VOLTAGE, None, byref(voltage))
if ret == 0:
    print(f"编程电压: {voltage.value / 1000:.2f} V")

C# 示例

uint voltage;
int ret = J2534.PassThruIoctl(deviceId, READ_PROG_VOLTAGE, IntPtr.Zero, out voltage);
if (ret == 0)
{
    Console.WriteLine($"编程电压: {voltage / 1000.0:F2} V");
}

FIVE_BAUD_INIT — 5 波特初始化

为 ISO 9141 和 ISO 14230(K-Line)协议启动慢速(5 波特)初始化。从 ECU 接收 KeyWord。初始化模式通过 SET_CONFIG 由参数 FIVE_BAUD_MOD 设置。通信速率会自动确定。

pInput SBYTE_ARRAY* — 初始化地址(1 字节)
pOutput SBYTE_ARRAY* — KeyWord(2 字节)
参数 FIVE_BAUD_MOD 决定初始化模式:ISO9141-2/ISO14230-4(0)、KB2 取反(1)、地址取反(2)、ISO9141 不取反(3)。

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long ChannelID;  // 由 PassThruConnect 返回
SBYTE_ARRAY InputMsg;
SBYTE_ARRAY OutputMsg;
long ret;

unsigned char initByte[1];
unsigned char keyWord[2];

initByte[0] = 0x33;  // ECU 初始化地址

InputMsg.NumOfBytes = 1;
InputMsg.BytePtr = initByte;
OutputMsg.NumOfBytes = 2;
OutputMsg.BytePtr = keyWord;

ret = PassThruIoctl(ChannelID, FIVE_BAUD_INIT, &InputMsg, &OutputMsg);
if (ret == STATUS_NOERROR)
{
    printf("KeyWord: %02X %02X\n", keyWord[0], keyWord[1]);
}

Kotlin (Android) 示例

// channelID 由 ptConnect 为 ISO14230 返回
val initAddress = byteArrayOf(0x33)  // 初始化地址

val result = j2534.ptFiveBaudInit(channelID, initAddress)
if (result.status == STATUS_NOERROR) {
    val keyWord = result.keyWord
    Log.i("J2534", "KeyWord: ${keyWord[0].toHex()} ${keyWord[1].toHex()}")
}

Python 示例

from ctypes import *

input_msg = SBYTE_ARRAY()
input_msg.NumOfBytes = 1
input_msg.BytePtr = (c_ubyte * 1)(0x33)

output_msg = SBYTE_ARRAY()
output_msg.NumOfBytes = 2
keyword = (c_ubyte * 2)()
output_msg.BytePtr = keyword

ret = j2534.PassThruIoctl(channel_id, FIVE_BAUD_INIT, byref(input_msg), byref(output_msg))
if ret == 0:
    print(f"KeyWord: {keyword[0]:02X} {keyword[1]:02X}")

C# 示例

var inputMsg = new SBYTE_ARRAY {
    NumOfBytes = 1,
    BytePtr = new byte[] { 0x33 }  // 初始化地址
};

var outputMsg = new SBYTE_ARRAY {
    NumOfBytes = 2,
    BytePtr = new byte[2]
};

int ret = J2534.PassThruIoctl(channelId, FIVE_BAUD_INIT, ref inputMsg, ref outputMsg);
if (ret == 0)
{
    Console.WriteLine($"KeyWord: {outputMsg.BytePtr[0]:X2} {outputMsg.BytePtr[1]:X2}");
}

FAST_INIT — Fast 初始化

为 ISO 14230(K-Line)协议启动快速初始化。发送 StartCommunication 请求并返回 ECU 的响应。用于 KWP2000。

pInput PASSTHRU_MSG* — 初始化请求
pOutput PASSTHRU_MSG* — ECU 响应
重要使用功能(广播)地址时,可能有多个 ECU 响应该请求。pOutput 中仅包含第一个响应,其余响应会进入接收队列。

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long ChannelID;  // 由 PassThruConnect 返回
PASSTHRU_MSG InputMsg;
PASSTHRU_MSG OutputMsg;
long ret;

// StartCommunication 请求
InputMsg.ProtocolID = ISO14230;
InputMsg.TxFlags = 0;
InputMsg.DataSize = 4;
InputMsg.Data[0] = 0x81;  // 格式:物理地址,1 字节数据
InputMsg.Data[1] = 0x10;  // 目标地址(ECU)
InputMsg.Data[2] = 0xF1;  // 源地址(测试仪)
InputMsg.Data[3] = 0x81;  // SID: StartCommunication

ret = PassThruIoctl(ChannelID, FAST_INIT, &InputMsg, &OutputMsg);
if (ret == STATUS_NOERROR)
{
    printf("ECU 响应: %d 字节\n", OutputMsg.DataSize);
    for (int i = 0; i < OutputMsg.DataSize; i++)
        printf("%02X ", OutputMsg.Data[i]);
}

Kotlin (Android) 示例

// channelID 由 ptConnect 为 ISO14230 返回
val request = PassThruMsg(
    protocolID = ISO14230,
    txFlags = 0u,
    dataSize = 4,
    data = byteArrayOf(0x81.toByte(), 0x10, 0xF1.toByte(), 0x81.toByte())
)

val result = j2534.ptFastInit(channelID, request)
if (result.status == STATUS_NOERROR) {
    Log.i("J2534", "ECU 响应: ${result.response.data.toHexString()}")
}

Python 示例

from ctypes import *

input_msg = PASSTHRU_MSG()
input_msg.ProtocolID = ISO14230
input_msg.TxFlags = 0
input_msg.DataSize = 4
input_msg.Data[0] = 0x81  # 格式
input_msg.Data[1] = 0x10  # 目标地址
input_msg.Data[2] = 0xF1  # 源地址
input_msg.Data[3] = 0x81  # SID: StartCommunication

output_msg = PASSTHRU_MSG()

ret = j2534.PassThruIoctl(channel_id, FAST_INIT, byref(input_msg), byref(output_msg))
if ret == 0:
    data = bytes(output_msg.Data[:output_msg.DataSize])
    print(f"ECU 响应: {data.hex(' ').upper()}")

C# 示例

var inputMsg = new PASSTHRU_MSG {
    ProtocolID = ISO14230,
    TxFlags = 0,
    DataSize = 4
};
inputMsg.Data[0] = 0x81;  // 格式
inputMsg.Data[1] = 0x10;  // 目标地址
inputMsg.Data[2] = 0xF1;  // 源地址
inputMsg.Data[3] = 0x81;  // SID: StartCommunication

var outputMsg = new PASSTHRU_MSG();

int ret = J2534.PassThruIoctl(channelId, FAST_INIT, ref inputMsg, ref outputMsg);
if (ret == 0)
{
    var data = new byte[outputMsg.DataSize];
    Array.Copy(outputMsg.Data, data, outputMsg.DataSize);
    Console.WriteLine($"ECU 响应: {BitConverter.ToString(data).Replace("-", " ")}");
}

CLEAR_TX_BUFFER — 清空发送队列

删除通道发送队列中的所有消息。用于取消已计划的发送。

pInput NULL
pOutput NULL

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long ChannelID;
long ret;

ret = PassThruIoctl(ChannelID, CLEAR_TX_BUFFER, NULL, NULL);
if (ret != STATUS_NOERROR)
{
    char error[256];
    PassThruGetLastError(error);
    printf("错误: %s\n", error);
}

Kotlin (Android) 示例

val result = j2534.ptIoctl(channelID, CLEAR_TX_BUFFER, 0, null)
if (result.status != STATUS_NOERROR) {
    Log.e("J2534", "CLEAR_TX_BUFFER 错误: ${result.status}")
}

Python 示例

ret = j2534.PassThruIoctl(channel_id, CLEAR_TX_BUFFER, None, None)
if ret != 0:
    print(f"CLEAR_TX_BUFFER 错误: {ret}")

C# 示例

int ret = J2534.PassThruIoctl(channelId, CLEAR_TX_BUFFER, IntPtr.Zero, IntPtr.Zero);
if (ret != 0)
    Console.WriteLine($"CLEAR_TX_BUFFER 错误: {ret}");

CLEAR_RX_BUFFER — 清空接收队列

删除通道接收队列中的所有消息。建议在开始新的诊断会话前调用。

pInput NULL
pOutput NULL

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long ChannelID;
long ret;

ret = PassThruIoctl(ChannelID, CLEAR_RX_BUFFER, NULL, NULL);
if (ret != STATUS_NOERROR)
{
    char error[256];
    PassThruGetLastError(error);
    printf("错误: %s\n", error);
}

Kotlin (Android) 示例

val result = j2534.ptIoctl(channelID, CLEAR_RX_BUFFER, 0, null)
if (result.status != STATUS_NOERROR) {
    Log.e("J2534", "CLEAR_RX_BUFFER 错误: ${result.status}")
}

Python 示例

ret = j2534.PassThruIoctl(channel_id, CLEAR_RX_BUFFER, None, None)
if ret != 0:
    print(f"CLEAR_RX_BUFFER 错误: {ret}")

C# 示例

int ret = J2534.PassThruIoctl(channelId, CLEAR_RX_BUFFER, IntPtr.Zero, IntPtr.Zero);
if (ret != 0)
    Console.WriteLine($"CLEAR_RX_BUFFER 错误: {ret}");

CLEAR_PERIODIC_MSGS — 清除周期性消息

删除通过 PassThruStartPeriodicMsg 设置的所有周期性消息。等同于对每条消息调用 PassThruStopPeriodicMsg。

pInput NULL
pOutput NULL

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long ChannelID;
long ret;

ret = PassThruIoctl(ChannelID, CLEAR_PERIODIC_MSGS, NULL, NULL);
if (ret != STATUS_NOERROR)
{
    char error[256];
    PassThruGetLastError(error);
    printf("错误: %s\n", error);
}

Kotlin (Android) 示例

val result = j2534.ptIoctl(channelID, CLEAR_PERIODIC_MSGS, 0, null)
if (result.status != STATUS_NOERROR) {
    Log.e("J2534", "CLEAR_PERIODIC_MSGS 错误: ${result.status}")
}

Python 示例

ret = j2534.PassThruIoctl(channel_id, CLEAR_PERIODIC_MSGS, None, None)
if ret != 0:
    print(f"CLEAR_PERIODIC_MSGS 错误: {ret}")

C# 示例

int ret = J2534.PassThruIoctl(channelId, CLEAR_PERIODIC_MSGS, IntPtr.Zero, IntPtr.Zero);
if (ret != 0)
    Console.WriteLine($"CLEAR_PERIODIC_MSGS 错误: {ret}");

CLEAR_MSG_FILTERS — 清除过滤器

删除通过 PassThruStartMsgFilter 设置的所有消息过滤器。调用后,在设置新过滤器之前,所有入站消息都将被阻止。

pInput NULL
pOutput NULL

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long ChannelID;
long ret;

ret = PassThruIoctl(ChannelID, CLEAR_MSG_FILTERS, NULL, NULL);
if (ret != STATUS_NOERROR)
{
    char error[256];
    PassThruGetLastError(error);
    printf("错误: %s\n", error);
}

Kotlin (Android) 示例

val result = j2534.ptIoctl(channelID, CLEAR_MSG_FILTERS, 0, null)
if (result.status != STATUS_NOERROR) {
    Log.e("J2534", "CLEAR_MSG_FILTERS 错误: ${result.status}")
}

Python 示例

ret = j2534.PassThruIoctl(channel_id, CLEAR_MSG_FILTERS, None, None)
if ret != 0:
    print(f"CLEAR_MSG_FILTERS 错误: {ret}")

C# 示例

int ret = J2534.PassThruIoctl(channelId, CLEAR_MSG_FILTERS, IntPtr.Zero, IntPtr.Zero);
if (ret != 0)
    Console.WriteLine($"CLEAR_MSG_FILTERS 错误: {ret}");

CLEAR_FUNCT_MSG_LOOKUP_TABLE — 清除功能寻址表

清除 J1850 功能寻址表。用于 J1850 PWM/VPW 协议在使用功能寻址时。

pInput NULL
pOutput NULL

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long ChannelID;  // J1850 通道
long ret;

ret = PassThruIoctl(ChannelID, CLEAR_FUNCT_MSG_LOOKUP_TABLE, NULL, NULL);
if (ret != STATUS_NOERROR)
{
    // 错误处理
}

Python 示例

ret = j2534.PassThruIoctl(channel_id, CLEAR_FUNCT_MSG_LOOKUP_TABLE, None, None)

C# 示例

int ret = J2534.PassThruIoctl(channelId, CLEAR_FUNCT_MSG_LOOKUP_TABLE, IntPtr.Zero, IntPtr.Zero);

ADD_TO_FUNCT_MSG_LOOKUP_TABLE — 添加功能地址

向 J1850 功能寻址表添加一个地址。使用功能寻址时将接收带有该地址的消息。

pInput SBYTE_ARRAY* — 要添加的地址列表
pOutput NULL

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long ChannelID;
SBYTE_ARRAY AddrList;
unsigned char addresses[3] = {0x10, 0x18, 0x28};  // ECU 地址
long ret;

AddrList.NumOfBytes = 3;
AddrList.BytePtr = addresses;

ret = PassThruIoctl(ChannelID, ADD_TO_FUNCT_MSG_LOOKUP_TABLE, &AddrList, NULL);
if (ret != STATUS_NOERROR)
{
    // 错误处理
}

Python 示例

addresses = (c_ubyte * 3)(0x10, 0x18, 0x28)
addr_list = SBYTE_ARRAY()
addr_list.NumOfBytes = 3
addr_list.BytePtr = addresses

ret = j2534.PassThruIoctl(channel_id, ADD_TO_FUNCT_MSG_LOOKUP_TABLE, byref(addr_list), None)

C# 示例

var addrList = new SBYTE_ARRAY {
    NumOfBytes = 3,
    BytePtr = new byte[] { 0x10, 0x18, 0x28 }
};
int ret = J2534.PassThruIoctl(channelId, ADD_TO_FUNCT_MSG_LOOKUP_TABLE, ref addrList, IntPtr.Zero);

DELETE_FROM_FUNCT_MSG_LOOKUP_TABLE — 删除功能地址

从 J1850 功能寻址表删除一个地址。

pInput SBYTE_ARRAY* — 要删除的地址列表
pOutput NULL

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long ChannelID;
SBYTE_ARRAY AddrList;
unsigned char addresses[1] = {0x10};  // 要删除的地址
long ret;

AddrList.NumOfBytes = 1;
AddrList.BytePtr = addresses;

ret = PassThruIoctl(ChannelID, DELETE_FROM_FUNCT_MSG_LOOKUP_TABLE, &AddrList, NULL);
if (ret != STATUS_NOERROR)
{
    // 错误处理
}

Python 示例

addresses = (c_ubyte * 1)(0x10)
addr_list = SBYTE_ARRAY()
addr_list.NumOfBytes = 1
addr_list.BytePtr = addresses

ret = j2534.PassThruIoctl(channel_id, DELETE_FROM_FUNCT_MSG_LOOKUP_TABLE, byref(addr_list), None)

C# 示例

var addrList = new SBYTE_ARRAY {
    NumOfBytes = 1,
    BytePtr = new byte[] { 0x10 }
};
int ret = J2534.PassThruIoctl(channelId, DELETE_FROM_FUNCT_MSG_LOOKUP_TABLE, ref addrList, IntPtr.Zero);

SW_CAN_HS — SW-CAN 高速模式

将 Single-Wire CAN 切换至高速模式(83.3 kbit/s)。用于在 GM 网络中进行高速诊断。

pInput NULL
pOutput NULL

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long ChannelID;  // SW-CAN 通道
long ret;

// 切换至高速模式
ret = PassThruIoctl(ChannelID, SW_CAN_HS, NULL, NULL);
if (ret == STATUS_NOERROR)
{
    printf("SW-CAN 处于 High Speed 模式 (83.3 kbit/s)\n");
}

Kotlin (Android) 示例

val result = j2534.ptIoctl(channelID, SW_CAN_HS, 0, null)
if (result.status == STATUS_NOERROR) {
    Log.i("J2534", "SW-CAN 处于 High Speed 模式 (83.3 kbit/s)")
}

Python 示例

ret = j2534.PassThruIoctl(channel_id, SW_CAN_HS, None, None)
if ret == 0:
    print("SW-CAN 处于 High Speed 模式 (83.3 kbit/s)")

C# 示例

int ret = J2534.PassThruIoctl(channelId, SW_CAN_HS, IntPtr.Zero, IntPtr.Zero);
if (ret == 0)
    Console.WriteLine("SW-CAN 处于 High Speed 模式 (83.3 kbit/s)");

SW_CAN_NS — SW-CAN 正常模式

将 Single-Wire CAN 切换至正常模式(33.3 kbit/s)。这是 GM 网络的默认模式。

pInput NULL
pOutput NULL

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long ChannelID;  // SW-CAN 通道
long ret;

// 切换至正常模式
ret = PassThruIoctl(ChannelID, SW_CAN_NS, NULL, NULL);
if (ret == STATUS_NOERROR)
{
    printf("SW-CAN 处于 Normal Speed 模式 (33.3 kbit/s)\n");
}

Kotlin (Android) 示例

val result = j2534.ptIoctl(channelID, SW_CAN_NS, 0, null)
if (result.status == STATUS_NOERROR) {
    Log.i("J2534", "SW-CAN 处于 Normal Speed 模式 (33.3 kbit/s)")
}

Python 示例

ret = j2534.PassThruIoctl(channel_id, SW_CAN_NS, None, None)
if ret == 0:
    print("SW-CAN 处于 Normal Speed 模式 (33.3 kbit/s)")

C# 示例

int ret = J2534.PassThruIoctl(channelId, SW_CAN_NS, IntPtr.Zero, IntPtr.Zero);
if (ret == 0)
    Console.WriteLine("SW-CAN 处于 Normal Speed 模式 (33.3 kbit/s)");

BUS_ON — 将控制器连接到总线 v5.0

将 CAN 控制器连接到物理总线。用于通过带 CAN_DISCONNECT 标志的 PassThruDisconnect 将控制器从总线断开后,或在打开通道而未自动连接后使用。

IoctlID 0x0F
pInput NULL
pOutput NULL
该命令仅在 J2534 v5.00 中可用。在 v04.04 中,控制器会在 PassThruConnect 时自动连接到总线。

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long ChannelID;  // CAN 通道
long ret;

// 将控制器连接到总线
ret = PassThruIoctl(ChannelID, BUS_ON, NULL, NULL);
if (ret == STATUS_NOERROR)
{
    printf("CAN 控制器已连接到总线\n");
}

Kotlin (Android) 示例

val result = j2534.ptIoctl(channelID, BUS_ON, 0, null)
if (result.status == STATUS_NOERROR) {
    Log.i("J2534", "CAN 控制器已连接到总线")
}

Python 示例

ret = j2534.PassThruIoctl(channel_id, BUS_ON, None, None)
if ret == 0:
    print("CAN 控制器已连接到总线")

C# 示例

int ret = J2534.PassThruIoctl(channelId, BUS_ON, IntPtr.Zero, IntPtr.Zero);
if (ret == 0)
    Console.WriteLine("CAN 控制器已连接到总线");

REQUEST_CONNECTION — 建立 TP 2.0 连接 J2534-2

请求在适配器与 ECU 之间建立 TP 2.0 通道和连接。用于 TP 2.0(VAG)协议。该命令为非阻塞——连接结果会作为指示进入接收队列。

IoctlID 0x800A
pInput SBYTE_ARRAY* — 连接请求数据(11 字节)
pOutput NULL

数据结构(11 字节)

BytePtr[0-3] CAN ID(标识符),BytePtr[0] 为高字节
BytePtr[4] Destination — 目标地址(ECU)
BytePtr[5] Opcode — 始终为 0xC0
BytePtr[6-7] TX-ID-A — 用于发送的 CAN ID
BytePtr[8-9] RX-ID-A — 用于接收的 CAN ID
BytePtr[10] Application Type — 应用类型
连接成功时,会为 RX-ID-A 创建一个隐式 PASS 过滤器。接收队列中会放入指示 CONNECTION_ESTABLISHED。出错时为 CONNECTION_LOST
如果 RX-ID-A 已被另一通道使用,则返回 ERR_NOT_UNIQUE。如果 NumOfBytes ≠ 11,则返回 ERR_INVALID_IOCTL_VALUE

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long ChannelID;  // TP 2.0 通道
SBYTE_ARRAY InputData;
unsigned char data[11];
long ret;

// 用于 broadcast 的 CAN ID: 0x200
data[0] = 0x00;
data[1] = 0x00;
data[2] = 0x02;
data[3] = 0x00;
// Destination(ECU 地址,例如发动机为 0x01)
data[4] = 0x01;
// Opcode(始终为 0xC0)
data[5] = 0xC0;
// TX-ID-A(用于发送的 CAN ID,例如 0x300)
data[6] = 0x03;
data[7] = 0x00;
// RX-ID-A(用于接收的 CAN ID,例如 0x301)
data[8] = 0x03;
data[9] = 0x01;
// Application Type(诊断为 0x01)
data[10] = 0x01;

InputData.NumOfBytes = 11;
InputData.BytePtr = data;

ret = PassThruIoctl(ChannelID, REQUEST_CONNECTION, &InputData, NULL);
if (ret == STATUS_NOERROR)
{
    printf("连接请求已发送,等待 CONNECTION_ESTABLISHED\n");
}
else if (ret == ERR_NOT_UNIQUE)
{
    printf("RX-ID-A 已被另一通道使用\n");
}

Kotlin (Android) 示例

// channelID — TP 2.0 通道
val data = byteArrayOf(
    0x00, 0x00, 0x02, 0x00,  // CAN ID: 0x200
    0x01,                     // Destination: ECU 0x01
    0xC0.toByte(),            // Opcode
    0x03, 0x00,               // TX-ID-A: 0x300
    0x03, 0x01,               // RX-ID-A: 0x301
    0x01                      // Application Type
)

val result = j2534.ptIoctl(channelID, REQUEST_CONNECTION, data.size, data)
when (result.status) {
    STATUS_NOERROR -> Log.i("TP2.0", "连接请求已发送")
    ERR_NOT_UNIQUE -> Log.e("TP2.0", "RX-ID-A 已被使用")
    else -> Log.e("TP2.0", "错误: ${result.status}")
}

Python 示例

from ctypes import *

data = (c_ubyte * 11)(
    0x00, 0x00, 0x02, 0x00,  # CAN ID: 0x200
    0x01,                     # Destination: ECU 0x01
    0xC0,                     # Opcode
    0x03, 0x00,               # TX-ID-A: 0x300
    0x03, 0x01,               # RX-ID-A: 0x301
    0x01                      # Application Type
)

input_data = SBYTE_ARRAY()
input_data.NumOfBytes = 11
input_data.BytePtr = data

ret = j2534.PassThruIoctl(channel_id, REQUEST_CONNECTION, byref(input_data), None)
if ret == 0:
    print("连接请求已发送,等待 CONNECTION_ESTABLISHED")
elif ret == ERR_NOT_UNIQUE:
    print("RX-ID-A 已被另一通道使用")

C# 示例

var data = new byte[] {
    0x00, 0x00, 0x02, 0x00,  // CAN ID: 0x200
    0x01,                     // Destination: ECU 0x01
    0xC0,                     // Opcode
    0x03, 0x00,               // TX-ID-A: 0x300
    0x03, 0x01,               // RX-ID-A: 0x301
    0x01                      // Application Type
};

var inputData = new SBYTE_ARRAY {
    NumOfBytes = 11,
    BytePtr = data
};

int ret = J2534.PassThruIoctl(channelId, REQUEST_CONNECTION, ref inputData, IntPtr.Zero);
if (ret == 0)
    Console.WriteLine("连接请求已发送,等待 CONNECTION_ESTABLISHED");
else if (ret == ERR_NOT_UNIQUE)
    Console.WriteLine("RX-ID-A 已被另一通道使用");

TEARDOWN_CONNECTION — 断开 TP 2.0 连接 J2534-2

断开适配器与 ECU 之间已建立的 TP 2.0 连接。该命令为非阻塞——断开确认会作为指示 CONNECTION_LOST 进入接收队列。

IoctlID 0x800B
pInput SBYTE_ARRAY* — 接收的 CAN ID(4 字节)
pOutput NULL

数据结构(4 字节)

BytePtr[0-3] RX-ID-A — 用于接收的 CAN ID(与 REQUEST_CONNECTION 中相同),BytePtr[0] 为高字节
断开连接后,RX-ID-A 的隐式 PASS 过滤器将被删除。通过 PassThruStartMsgFilter 设置的过滤器仍保持有效。

C/C++ 示例

#include "j2534_dll.hpp"

unsigned long ChannelID;  // TP 2.0 通道
SBYTE_ARRAY InputData;
unsigned char data[4];
long ret;

// RX-ID-A(与 REQUEST_CONNECTION 中相同)
data[0] = 0x00;
data[1] = 0x00;
data[2] = 0x03;
data[3] = 0x01;  // 0x301

InputData.NumOfBytes = 4;
InputData.BytePtr = data;

ret = PassThruIoctl(ChannelID, TEARDOWN_CONNECTION, &InputData, NULL);
if (ret == STATUS_NOERROR)
{
    printf("连接断开请求已发送\n");
}

Kotlin (Android) 示例

// RX-ID-A: 0x301
val data = byteArrayOf(0x00, 0x00, 0x03, 0x01)

val result = j2534.ptIoctl(channelID, TEARDOWN_CONNECTION, data.size, data)
if (result.status == STATUS_NOERROR) {
    Log.i("TP2.0", "连接断开请求已发送")
}

Python 示例

from ctypes import *

# RX-ID-A: 0x301
data = (c_ubyte * 4)(0x00, 0x00, 0x03, 0x01)

input_data = SBYTE_ARRAY()
input_data.NumOfBytes = 4
input_data.BytePtr = data

ret = j2534.PassThruIoctl(channel_id, TEARDOWN_CONNECTION, byref(input_data), None)
if ret == 0:
    print("连接断开请求已发送")

C# 示例

// RX-ID-A: 0x301
var data = new byte[] { 0x00, 0x00, 0x03, 0x01 };

var inputData = new SBYTE_ARRAY {
    NumOfBytes = 4,
    BytePtr = data
};

int ret = J2534.PassThruIoctl(channelId, TEARDOWN_CONNECTION, ref inputData, IntPtr.Zero);
if (ret == 0)
    Console.WriteLine("连接断开请求已发送");