Kvaser CANlib SDK
概述
Kvaser CANlib SDK 是 Kvaser 官方提供的软件开发包,适用于 Kvaser CAN、CAN FD、LIN、远程 CAN 设备以及部分记录仪设备的二次开发。开发者可基于该 SDK 完成设备枚举、通道打开、总线参数配置、报文收发、状态读取、错误处理、日志转换、数据库解析以及远程设备管理等工作。
在实际项目中,CANlib 主要用于与连接到计算机和 CAN 总线的 Kvaser CAN 设备进行交互。其核心能力包括:
- 识别和枚举 Kvaser CAN 设备;
- 打开和关闭 CAN 通道;
- 配置 Classic CAN 或 CAN FD 总线参数;
- 控制 Bus On / Bus Off;
- 发送和接收 CAN / CAN FD 报文;
- 读取通道状态、错误状态和时间戳;
- 配合 Kvaser 工具链完成测试、调试和自动化验证。
开发包获取
开发前需要安装 Kvaser 官方 CANlib SDK。
Kvaser官方下载地址: <www.kvaser.cn/support/developer/canlib-sdk/>
SDK主要内容
Kvaser CANlib SDK 并不只是一个 CAN 收发库,而是一套较完整的 Kvaser 二次开发工具包。常见组成包括:
| 组件 | 用途 |
|---|---|
| CANlib | 最核心的 CAN 通讯库,用于与 Kvaser CAN 设备进行交互。 |
| LINlib | 用于 LIN 总线开发,功能与 CANlib 类似。 |
| kvaDbLib | Kvaser 的 CAN 数据库操作库,用于创建、读取、写入和修改 CAN 数据库文件。 |
| kvlclib | 日志文件转换库,主要用于转换 Kvaser Memorator 记录仪生成的日志文件。 |
| kvmlib | 主要用于与 Kvaser Memorator 记录仪设备交互。 |
| kvaMemoLibXML | 用于将 XML 格式的记录仪配置转换为 Kvaser Memorator 可使用的二进制配置文件,通常与 kvmlib 配合开发自定义记录仪配置工具。 |
| kvrlib | 主要用于 Kvaser 远程设备的发现和配置,例如通过以太网或 WiFi 连接的 Kvaser 设备。 |
虚拟硬件与虚拟通道
Kvaser CANlib SDK 提供虚拟硬件和虚拟 CAN 通道。虚拟通道可以在没有真实 Kvaser 硬件的情况下进行程序开发、功能演示和接口调试。
虚拟通道常用于以下场景:
- 开发初期没有真实设备;
- 上位机界面功能验证;
- 自动化测试流程调试;
- CAN 报文收发逻辑验证;
- 给客户演示软件功能。
使用虚拟通道时,需要安装 Kvaser 虚拟驱动程序。代码中通常可以使用允许虚拟通道的打开参数,例如:
canOpenChannel(channel, canOPEN_ACCEPT_VIRTUAL);需要注意的是,虚拟通道只能用于软件逻辑测试,不能代替真实 CAN 总线的电气层测试、负载测试、ACK 测试和错误帧测试。
支持的开发语言和编译环境
Kvaser CANlib SDK 支持多种开发语言和编译环境,常见包括:
- C / C++;
- C#;
- .NET;
- Managed C++;
- Visual Basic;
- Delphi;
- gcc;
- MinGW;
- Python 示例或第三方绑定;
- 其他可调用动态库的语言环境。
CANlib 典型调用流程
Classic CAN 调用流程
Classic CAN 项目的典型调用流程如下:
- 初始化 CANlib;
- 获取系统中的 CAN 通道数量;
- 读取通道名称、设备型号、EAN、序列号等信息;
- 打开目标通道;
- 设置 CAN 波特率;
- 设置驱动模式,例如 Normal、Silent;
- 执行 Bus On;
- 发送 CAN 报文;
- 接收 CAN 报文;
- 读取总线状态和错误信息;
- 测试结束后执行 Bus Off;
- 关闭通道句柄。
C/C++ 通道枚举示例
#include <canlib.h>
#include <iostream>
int main()
{
canInitializeLibrary();
int channelCount = 0;
canStatus status = canGetNumberOfChannels(&channelCount);
if (status != canOK)
{
std::cout << "canGetNumberOfChannels failed." << std::endl;
return -1;
}
std::cout << "Detected Kvaser channels: "
<< channelCount
<< std::endl;
for (int ch = 0; ch < channelCount; ch++)
{
char channelName[128] = {0};
status = canGetChannelData(
ch,
canCHANNELDATA_CHANNEL_NAME,
channelName,
sizeof(channelName));
if (status == canOK)
{
std::cout << "Channel "
<< ch
<< " : "
<< channelName
<< std::endl;
}
}
return 0;
}实际项目中还可以继续读取设备 EAN、序列号、硬件类型等信息,用于多设备绑定和通道自动匹配。
Classic CAN 发送示例
以下示例演示 500 kbit/s Classic CAN 报文发送流程。
#include <canlib.h>
#include <iostream>
static void printError(canStatus status)
{
char errorText[128] = {0};
canGetErrorText(status, errorText, sizeof(errorText));
std::cout << "CANlib error: " << errorText << std::endl;
}
int main()
{
canInitializeLibrary();
int channel = 0;
canHandle handle = canOpenChannel(
channel,
canOPEN_ACCEPT_VIRTUAL);
if (handle < 0)
{
printError((canStatus)handle);
return -1;
}
canStatus status;
status = canSetBusParams(
handle,
canBITRATE_500K,
0,
0,
0,
0,
0);
if (status != canOK)
{
printError(status);
canClose(handle);
return -1;
}
status = canSetBusOutputControl(
handle,
canDRIVER_NORMAL);
if (status != canOK)
{
printError(status);
canClose(handle);
return -1;
}
status = canBusOn(handle);
if (status != canOK)
{
printError(status);
canClose(handle);
return -1;
}
unsigned char data[8] = {
0x01,
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08
};
status = canWrite(
handle,
0x123,
data,
8,
0);
if (status != canOK)
{
printError(status);
}
status = canWriteSync(
handle,
100);
if (status != canOK)
{
printError(status);
}
canBusOff(handle);
canClose(handle);
return 0;
}CAN FD 发送示例
以下示例演示 CAN FD 报文发送流程。实际项目中,仲裁段和数据段波特率应根据网络中所有节点的配置保持一致。
#include <canlib.h>
#include <iostream>
static void printError(canStatus status)
{
char errorText[128] = {0};
canGetErrorText(status, errorText, sizeof(errorText));
std::cout << "CANlib error: " << errorText << std::endl;
}
int main()
{
canInitializeLibrary();
int channel = 0;
canHandle handle = canOpenChannel(
channel,
canOPEN_CAN_FD | canOPEN_ACCEPT_VIRTUAL);
if (handle < 0)
{
printError((canStatus)handle);
return -1;
}
canStatus status;
/*
* 仲裁段波特率。
* 示例使用 1 Mbit/s,采样点 80%。
* 具体宏定义以实际 SDK 头文件为准。
*/
status = canSetBusParams(
handle,
canFD_BITRATE_1M_80P,
0,
0,
0,
0,
0);
if (status != canOK)
{
printError(status);
canClose(handle);
return -1;
}
/*
* 数据段波特率。
* 示例使用 4 Mbit/s,采样点 80%。
*/
status = canSetBusParamsFd(
handle,
canFD_BITRATE_4M_80P,
0,
0,
0);
if (status != canOK)
{
printError(status);
canClose(handle);
return -1;
}
status = canSetBusOutputControl(
handle,
canDRIVER_NORMAL);
if (status != canOK)
{
printError(status);
canClose(handle);
return -1;
}
status = canBusOn(handle);
if (status != canOK)
{
printError(status);
canClose(handle);
return -1;
}
unsigned char data[64] = {0};
for (int i = 0; i < 64; i++)
{
data[i] = (unsigned char)i;
}
/*
* canFDMSG_FDF 表示 CAN FD 帧。
* canFDMSG_BRS 表示使用数据段加速。
* 如果不启用 BRS,可只使用 canFDMSG_FDF。
*/
unsigned int flags = canFDMSG_FDF | canFDMSG_BRS;
status = canWrite(
handle,
0x123,
data,
64,
flags);
if (status != canOK)
{
printError(status);
}
status = canWriteSync(
handle,
100);
if (status != canOK)
{
printError(status);
}
canBusOff(handle);
canClose(handle);
return 0;
}接收报文示例
CANlib 可通过 canRead() 读取接收队列中的报文。接收时需要注意区分 Classic CAN 和 CAN FD 报文标志。
long id = 0;
unsigned char data[64] = {0};
unsigned int dlc = 0;
unsigned int flags = 0;
unsigned long timestamp = 0;
canStatus status = canRead(
handle,
&id,
data,
&dlc,
&flags,
×tamp);
if (status == canOK)
{
std::cout << "ID: 0x"
<< std::hex
<< id
<< " DLC: "
<< std::dec
<< dlc
<< " Timestamp: "
<< timestamp
<< std::endl;
if (flags & canFDMSG_FDF)
{
std::cout << "CAN FD frame" << std::endl;
}
else
{
std::cout << "Classic CAN frame" << std::endl;
}
}
else if (status == canERR_NOMSG)
{
/*
* 当前无报文,不属于严重错误。
* 可以继续轮询,或使用事件机制等待接收。
*/
}
else
{
printError(status);
}对于高实时性或高负载项目,不建议用简单死循环一直轮询,可结合事件通知、接收线程或系统等待机制进行优化。
错误处理
CANlib 的大多数接口都会返回 canStatus 状态码。开发中应检查所有关键 API 的返回值,并通过 canGetErrorText() 输出可读错误信息。
canStatus status = canBusOn(handle);
if (status != canOK)
{
char errorText[128] = {0};
canGetErrorText(
status,
errorText,
sizeof(errorText));
printf("canBusOn failed: %s\n", errorText);
}建议重点关注以下错误或状态:
- 通道打开失败;
- 参数配置失败;
- Bus On 失败;
- 发送超时;
- 接收队列为空;
- TX 队列满;
- Bus Heavy;
- Bus Off;
- ACK Error;
- Error Frame;
- 硬件断开;
- 驱动未安装或版本不匹配。
Python 开发方式
Python 项目通常适合自动化测试、脚本化验证和快速调试。常见方式有两种。
1. 使用 python-can
python-can 可以通过 interface="kvaser" 调用 Kvaser 后端。
Classic CAN 示例:
import can
bus = can.Bus(
interface="kvaser",
channel=0,
bitrate=500000
)
msg = can.Message(
arbitration_id=0x123,
data=[1, 2, 3, 4],
is_extended_id=False
)
bus.send(msg)
bus.shutdown()CAN FD 示例:
import can
bus = can.Bus(
interface="kvaser",
channel=0,
bitrate=1000000,
data_bitrate=4000000,
fd=True
)
msg = can.Message(
arbitration_id=0x123,
data=bytes(range(64)),
is_extended_id=False,
is_fd=True,
bitrate_switch=True
)
bus.send(msg)
bus.shutdown()使用 python-can 时,仍然需要先安装 Kvaser 驱动和 CANlib 运行环境,否则 Kvaser 后端无法正常工作。
2. 使用 Kvaser 官方 Python CANlib 包
也可以使用 Kvaser 官方 Python CANlib 包进行开发。
安装方式通常为:
pip install canlib示例代码需要根据当前 Python CANlib 包版本编写。不同版本的类名和接口封装可能略有变化,因此正式项目中建议以安装包自带示例和官方文档为准。
