API 编程接口

Alius USB2CAN 双路调试器提供开源的 CANAL API DLL,方便开发者通过编程方式控制设备。本文档详细介绍了 API 的使用方法、函数说明和代码示例,帮助您快速集成 Alius USB2CAN 调试器到您的应用程序中。

CANAL API 概述

CANAL(CAN Abstraction Layer)是一个开源的 CAN 总线抽象层 API,提供了一套统一的接口函数来访问各种 CAN 接口设备。Alius USB2CAN 调试器完全支持 CANAL API,使得开发者可以编写与硬件无关的应用程序。

API 特点

  • 跨平台:支持 Windows 和 Linux 操作系统
  • 多语言支持:支持 C/C++、C#、Python、Java、LabVIEW 等多种编程语言
  • 开源:源代码开放,可根据需要进行修改和定制
  • 易于使用:提供简洁、直观的 API 函数

安装与配置

Windows 环境

  1. 将 CANAL API DLL(通常为 canal.dll)复制到您的应用程序目录或系统目录(如 C:\Windows\System32
  2. 在您的项目中添加 CANAL API 头文件(canal.h
  3. 配置项目链接到 CANAL API 库

Linux 环境

  1. 安装 CANAL API 共享库(通常为 libcanal.so
  2. 在您的项目中包含 CANAL API 头文件
  3. 编译时链接 CANAL API 库(使用 -lcanal 选项)

API 函数说明

1. 打开连接

long CanalOpen(char *pDevice, unsigned long flags);

功能:打开与 CAN 设备的连接

参数

  • pDevice:设备名称或路径(例如,COM 端口号)
  • flags:打开标志(通常设置为 0)

返回值

  • 成功:返回设备句柄(> 0)
  • 失败:返回 0

示例

long hDevice = CanalOpen("COM3", 0);
if (0 == hDevice) {
    printf("无法打开设备\n");
    return -1;
}

2. 关闭连接

int CanalClose(long handle);

功能:关闭与 CAN 设备的连接

参数

  • handle:设备句柄(由 CanalOpen 返回)

返回值

  • 成功:返回 1
  • 失败:返回 0

示例

if (0 == CanalClose(hDevice)) {
    printf("关闭设备失败\n");
}

3. 获取设备状态

int CanalGetStatus(long handle, canalsystemstatus *pStatus);

功能:获取设备的当前状态

参数

  • handle:设备句柄
  • pStatus:指向 canalsystemstatus 结构的指针

返回值

  • 成功:返回 1
  • 失败:返回 0

4. 获取统计信息

int CanalGetStatistics(long handle, canalstatistics *pStatistics);

功能:获取设备的通信统计信息

参数

  • handle:设备句柄
  • pStatistics:指向 canalstatistics 结构的指针

返回值

  • 成功:返回 1
  • 失败:返回 0

5. 发送 CAN 报文

int CanalSend(long handle, canalmsg *pCanMsg);

功能:发送一个 CAN 报文

参数

  • handle:设备句柄
  • pCanMsg:指向 canalmsg 结构的指针

返回值

  • 成功:返回 1
  • 失败:返回 0

示例

canalmsg canMsg;
memset(&canMsg, 0, sizeof(canalmsg));

canMsg.id = 0x100;          // CAN 报文 ID
canMsg.flags = 0;            // 标准帧,无 RTR
canMsg.sizeData = 8;         // 数据长度
canMsg.data[0] = 0x01;      // 数据字节 0
canMsg.data[1] = 0x02;      // 数据字节 1
// ... 设置其他数据字节

if (0 == CanalSend(hDevice, &canMsg)) {
    printf("发送报文失败\n");
}

6. 接收 CAN 报文

int CanalReceive(long handle, canalmsg *pCanMsg);

功能:接收一个 CAN 报文

参数

  • handle:设备句柄
  • pCanMsg:指向 canalmsg 结构的指针

返回值

  • 成功:返回 1
  • 失败:返回 0
  • 无报文:返回 0(需要检查 pCanMsg->sizeData

示例

canalmsg canMsg;
memset(&canMsg, 0, sizeof(canalmsg));

if (CanalReceive(hDevice, &canMsg)) {
    printf("收到报文:ID=0x%X, DLC=%d\n", canMsg.id, canMsg.sizeData);
    for (int i = 0; i < canMsg.sizeData; i++) {
        printf("%02X ", canMsg.data[i]);
    }
    printf("\n");
} else {
    printf("接收报文失败或无报文\n");
}

7. 设置过滤器

int CanalSetFilter(long handle, unsigned long filter);

功能:设置硬件验收过滤器

参数

  • handle:设备句柄
  • filter:过滤器值

返回值

  • 成功:返回 1
  • 失败:返回 0

8. 设置屏蔽

int CanalSetMask(long handle, unsigned long mask);

功能:设置验收屏蔽

参数

  • handle:设备句柄
  • mask:屏蔽值

返回值

  • 成功:返回 1
  • 失败:返回 0

数据结构

canalmsg 结构

typedef struct {
    unsigned long id;        // CAN 报文 ID
    unsigned char flags;     // 标志位
    unsigned char sizeData;  // 数据长度(0-8)
    unsigned char data[8];   // 数据字节
    unsigned long timestamp; // 时间戳(ms)
} canalmsg;

标志位定义

  • 0x00:标准帧(11 位 ID)
  • 0x01:扩展帧(29 位 ID)
  • 0x02:远程帧(RTR)

canalsystemstatus 结构

typedef struct {
    unsigned long channel_status;  // 通道状态
    unsigned long lasterrorcode;  // 最后一个错误代码
    unsigned long lasterrorsource;// 最后一个错误源
    unsigned long errorcounter;   // 错误计数器
} canalsystemstatus;

canalstatistics 结构

typedef struct {
    unsigned long cntReceiveFrames;  // 接收帧计数
    unsigned long cntTransmitFrames; // 发送帧计数
    unsigned long cntReceiveData;    // 接收数据字节计数
    unsigned long cntTransmitData;   // 发送数据字节计数
    unsigned long cntOverruns;       // 溢出计数
    unsigned long cntBusWarnings;    // 总线警告计数
    unsigned long cntBusOff;         // 总线关闭计数
} canalstatistics;

代码示例

C++ 示例

#include <stdio.h>
#include "canal.h"

int main() {
    // 打开设备
    long hDevice = CanalOpen("COM3", 0);
    if (0 == hDevice) {
        printf("无法打开设备\n");
        return -1;
    }
    
    printf("设备打开成功,句柄:%ld\n", hDevice);
    
    // 发送报文
    canalmsg txMsg;
    memset(&txMsg, 0, sizeof(canalmsg));
    txMsg.id = 0x100;
    txMsg.sizeData = 8;
    for (int i = 0; i < 8; i++) {
        txMsg.data[i] = i;
    }
    
    if (CanalSend(hDevice, &txMsg)) {
        printf("报文发送成功\n");
    } else {
        printf("报文发送失败\n");
    }
    
    // 接收报文(等待 1 秒)
    canalmsg rxMsg;
    memset(&rxMsg, 0, sizeof(canalmsg));
    
    for (int i = 0; i < 100; i++) {
        if (CanalReceive(hDevice, &rxMsg)) {
            printf("收到报文:ID=0x%X, DLC=%d, 数据:", rxMsg.id, rxMsg.sizeData);
            for (int j = 0; j < rxMsg.sizeData; j++) {
                printf("%02X ", rxMsg.data[j]);
            }
            printf("\n");
        }
        Sleep(10);  // 等待 10 ms
    }
    
    // 关闭设备
    CanalClose(hDevice);
    
    return 0;
}

Python 示例

import ctypes
import time

# 加载 CANAL DLL
canal = ctypes.CDLL("canal.dll")

# 定义数据结构
class CanalMsg(ctypes.Structure):
    _fields_ = [
        ("id", ctypes.c_ulong),
        ("flags", ctypes.c_ubyte),
        ("sizeData", ctypes.c_ubyte),
        ("data", ctypes.c_ubyte * 8),
        ("timestamp", ctypes.c_ulong)
    ]

# 打开设备
hDevice = canal.CanalOpen("COM3", 0)
if 0 == hDevice:
    print("无法打开设备")
    exit(-1)

print(f"设备打开成功,句柄:{hDevice}")

# 发送报文
txMsg = CanalMsg()
txMsg.id = 0x100
txMsg.sizeData = 8
for i in range(8):
    txMsg.data[i] = i

if canal.CanalSend(hDevice, ctypes.byref(txMsg)):
    print("报文发送成功")
else:
    print("报文发送失败")

# 接收报文
rxMsg = CanalMsg()
for i in range(100):
    if canal.CanalReceive(hDevice, ctypes.byref(rxMsg)):
        print(f"收到报文:ID=0x{rxMsg.id:X}, DLC={rxMsg.sizeData}, 数据:", end="")
        for j in range(rxMsg.sizeData):
            print(f"{rxMsg.data[j]:02X} ", end="")
        print()
    time.sleep(0.01)

# 关闭设备
canal.CanalClose(hDevice)

高级功能

1. 多通道操作

Alius USB2CAN 调试器支持两个独立的 CAN 通道。您可以通过打开多个设备句柄来同时操作两个通道。

2. 错误处理

在使用过程中,可能会遇到各种错误,如总线关闭、接收溢出等。建议您定期检查设备状态,并根据错误类型采取相应的措施。

3. 性能优化

  • 使用硬件过滤器减少不必要的数据接收
  • 使用较大的接收缓冲区
  • 在单独的线程中处理接收的数据

常见问题

问题 1:无法加载 CANAL DLL

解决方法:确保 DLL 文件位于正确的路径,并检查 DLL 的依赖项是否满足。

问题 2:发送报文失败

解决方法:检查设备是否已打开、CAN 总线是否连接正确、波特率是否匹配。

问题 3:接收报文丢失

解决方法:增加接收缓冲区大小、及时处理接收到的报文、降低波特率。

技术支持

如果您在使用过程中遇到任何问题,请联系 Alius 技术支持团队。我们将竭诚为您服务。