在物理连接之上创建逻辑通信通道
最后修改:
该函数在指定的 pass-thru 设备上创建与车辆的逻辑通信通道。逻辑通道在现有的物理通信通道之上叠加额外的协议方案。
执行成功时函数返回 STATUS_NOERROR,指针 pChannelID 所指向的值用作所创建通道的描述符(handle)。通道处于已初始化状态。
每个物理通信通道最多允许 10 个逻辑通道。创建逻辑通道不会影响物理通道及与其关联的其他逻辑通道的运行。
long PassThruLogicalConnect(
unsigned long PhysicalChannelID,
unsigned long ProtocolID,
unsigned long Flags,
void *pChannelDescriptor,
unsigned long *pChannelID
)
所创建的逻辑通道具有以下初始状态:
输入参数。调用 PassThruConnect() 时获得的物理通道标识符。
输入参数。逻辑通信通道的协议标识符。它决定逻辑通道如何与车辆交互,以及 pChannelDescriptor 结构体的类型。
| ProtocolID | 说明 |
|---|---|
ISO15765_LOGICAL |
带流控(flow control)的 ISO 15765-2 |
输入参数。逻辑通道的配置标志。各标志可通过 OR 组合。
| 标志 | 说明 | 取值 |
|---|---|---|
FULL_DUPLEX |
通道的双工模式。仅适用于 ISO 15765。 | 0 = 半双工 1 = 全双工 |
ISO15765_ON_J1939 |
针对采用 29 位标识符的 ISO 15765 消息,对 CAN ID 中的优先级位(28-26)进行屏蔽(依据 ISO 15765-2 Annex A 和 SAE J1939-21)。仅适用于 ISO 15765。 | 0 = 关闭屏蔽(标准 ISO 15765 处理) 1 = 开启屏蔽 |
输入参数。指向描述逻辑连接端点的结构体的指针。若指针为 NULL,函数将返回 ERR_NULL_PARAMETER。
输入参数。指向由应用程序分配的 unsigned long 变量的指针。执行成功时,该变量将包含逻辑通道标识符,供后续函数调用使用。
对于协议 ISO15765_LOGICAL,使用 ISO15765_CHANNEL_DESCRIPTOR 结构体来定义逻辑连接的端点:
typedef struct {
unsigned long LocalTxFlags; // LocalAddress 的 TxFlags
unsigned long RemoteTxFlags; // RemoteAddress 的 TxFlags
unsigned char LocalAddress[5]; // CAN ID + extended address(本地端)
unsigned char RemoteAddress[5]; // CAN ID + extended address(远端)
} ISO15765_CHANNEL_DESCRIPTOR;
ISO 15765 通道描述符的有效标志:
| 标志 | 适用于 | 说明 |
|---|---|---|
CAN_29BIT_ID |
LocalAddress, RemoteAddress | 使用 29 位 CAN ID(而非 11 位) |
ISO15765_ADDR_TYPE |
LocalAddress, RemoteAddress | 使用扩展寻址(extended address) |
ISO15765_FRAME_PAD |
RemoteAddress | 发送时对 flow control 帧启用填充(padding) |
Address[0] — CAN ID 位 28-24(高 3 位须为零)Address[1] — CAN ID 位 23-16Address[2] — CAN ID 位 15-8Address[3] — CAN ID 位 7-0Address[4] — 扩展地址(若指定了标志 ISO15765_ADDR_TYPE)LocalAddress 和 RemoteAddress 必须唯一。任何一个地址都不得与该物理通道下其他现有逻辑通道的地址相同。带扩展地址的 CAN ID 不得与不带扩展地址的 CAN ID 相同。
| 代码 | 说明 |
|---|---|
| STATUS_NOERROR | 函数执行成功 |
| ERR_CONCURRENT_API_CALL | 在上一次 J2534 API 调用完成之前再次调用了该函数 |
| ERR_DEVICE_NOT_OPEN | 未成功调用 PassThruOpen() |
| ERR_INVALID_CHANNEL_ID | PhysicalChannelID 取值无效 |
| ERR_DEVICE_NOT_CONNECTED | 与 pass-thru 设备的通信出错。设备已断开连接。 |
| ERR_NOT_SUPPORTED | DLL 不支持该函数 |
| ERR_LOG_CHAN_NOT_ALLOWED | 对该物理通道与 ProtocolID 的组合不允许逻辑通道 |
| ERR_PROTOCOL_ID_NOT_SUPPORTED | ProtocolID 取值不受支持(无效或未知) |
| ERR_FLAG_NOT_SUPPORTED | Flags 取值无效、未知或不适用于当前通道 |
| ERR_INVALID_CHANNEL_DESCRIPTOR | pChannelDescriptor 结构体的一个或多个元素无效或不适用于当前通道 |
| ERR_NULL_REQUIRED | 本应为 NULL 的参数未设置为 NULL |
| ERR_NULL_PARAMETER | 在必需指针处传入了 NULL 指针 |
| ERR_NOT_UNIQUE | 试图创建的逻辑通道其地址与现有通道的地址重复 |
| ERR_EXCEEDED_LIMIT | 超出了该物理通道的逻辑通道最大数量 |
| ERR_FAILED | 未定义的错误。请使用 PassThruGetLastError() 获取描述。 |
#include "j2534_dll.hpp"
unsigned long deviceID = 0;
unsigned long physicalChannelID = 0;
unsigned long logicalChannelID = 0;
// 打开设备
long ret = PassThruOpen("ScanDoc", &deviceID);
if (ret != STATUS_NOERROR) return;
// 创建 CAN 物理连接
ret = PassThruConnect(deviceID, CAN, CAN_29BIT_ID, 500000, &physicalChannelID);
if (ret != STATUS_NOERROR) {
PassThruClose(deviceID);
return;
}
// 配置 ISO 15765 逻辑通道描述符
ISO15765_CHANNEL_DESCRIPTOR channelDesc = {0};
// 本地地址(适配器)- 0x18DA00F1(功能寻址请求)
channelDesc.LocalTxFlags = CAN_29BIT_ID;
channelDesc.LocalAddress[0] = 0x18;
channelDesc.LocalAddress[1] = 0xDA;
channelDesc.LocalAddress[2] = 0x00;
channelDesc.LocalAddress[3] = 0xF1;
// 远端地址(ECU)- 0x18DAF100(来自 ECU 的响应)
channelDesc.RemoteTxFlags = CAN_29BIT_ID | ISO15765_FRAME_PAD;
channelDesc.RemoteAddress[0] = 0x18;
channelDesc.RemoteAddress[1] = 0xDA;
channelDesc.RemoteAddress[2] = 0xF1;
channelDesc.RemoteAddress[3] = 0x00;
// 创建逻辑通道
ret = PassThruLogicalConnect(
physicalChannelID,
ISO15765_LOGICAL,
0, // Flags: 半双工
&channelDesc,
&logicalChannelID
);
if (ret == STATUS_NOERROR) {
printf("逻辑通道已创建: %lu\n", logicalChannelID);
// 现在可以将 logicalChannelID 用于 PassThruReadMsgs/PassThruQueueMsgs
// 关闭逻辑通道
PassThruLogicalDisconnect(logicalChannelID);
}
// 关闭物理通道和设备
PassThruDisconnect(physicalChannelID);
PassThruClose(deviceID);
from ctypes import *
# 加载库
j2534 = cdll.LoadLibrary("libj2534_v05_00.dylib")
# 通道描述符结构体
class ISO15765_CHANNEL_DESCRIPTOR(Structure):
_fields_ = [
("LocalTxFlags", c_ulong),
("RemoteTxFlags", c_ulong),
("LocalAddress", c_ubyte * 5),
("RemoteAddress", c_ubyte * 5)
]
device_id = c_ulong()
physical_channel_id = c_ulong()
logical_channel_id = c_ulong()
# 打开设备
ret = j2534.PassThruOpen(b"ScanDoc", byref(device_id))
if ret != 0:
print(f"PassThruOpen 出错: {ret}")
exit()
# 创建 CAN 物理连接(500 kbit/s, 29-bit ID)
CAN = 0x05
CAN_29BIT_ID = 0x100
ret = j2534.PassThruConnect(device_id, CAN, CAN_29BIT_ID, 500000, byref(physical_channel_id))
if ret != 0:
print(f"PassThruConnect 出错: {ret}")
j2534.PassThruClose(device_id)
exit()
# 配置通道描述符
ISO15765_LOGICAL = 0x200
ISO15765_FRAME_PAD = 0x40
channel_desc = ISO15765_CHANNEL_DESCRIPTOR()
channel_desc.LocalTxFlags = CAN_29BIT_ID
channel_desc.LocalAddress[0] = 0x18
channel_desc.LocalAddress[1] = 0xDA
channel_desc.LocalAddress[2] = 0x00
channel_desc.LocalAddress[3] = 0xF1
channel_desc.RemoteTxFlags = CAN_29BIT_ID | ISO15765_FRAME_PAD
channel_desc.RemoteAddress[0] = 0x18
channel_desc.RemoteAddress[1] = 0xDA
channel_desc.RemoteAddress[2] = 0xF1
channel_desc.RemoteAddress[3] = 0x00
# 创建逻辑通道
ret = j2534.PassThruLogicalConnect(
physical_channel_id,
ISO15765_LOGICAL,
0,
byref(channel_desc),
byref(logical_channel_id)
)
if ret == 0:
print(f"逻辑通道已创建: {logical_channel_id.value}")
# ...使用通道...
j2534.PassThruLogicalDisconnect(logical_channel_id)
else:
print(f"出错: {ret}")
j2534.PassThruDisconnect(physical_channel_id)
j2534.PassThruClose(device_id)
PassThruConnect() - 创建物理连接PassThruLogicalDisconnect() - 关闭逻辑通道PassThruReadMsgs() - 从通道读取消息