news 2026/10/27 1:53:23

CANoe 模型库实战:OSEK_TP.dll 与 CANoeILNLVector.dll 函数详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CANoe 模型库实战:OSEK_TP.dll 与 CANoeILNLVector.dll 函数详解

目录

前言

一、OSEK_TP.dll

1. 加载 OSEK_TP.dll 文件

2. 常用函数介绍

3. 回调函数介绍

4. 修改诊断字节未使用的默认值

5. 修改流控帧参数

二、CANoeILNLVector.dll

1. 加载 CANoeILNLVector.dll 文件

2. IL 层控制函数

3. IL 层故障注入

4. 仿真 Counter 和 CRC

1. applILTxPending 函数

2. 定时器实现

总结


前言

CANoe 软件通过内置的模型库进一步拓展了 CANoe 的功能,每个模型库都是由一系列函数组成的,封装成一个 DLL 文件。用户可以在 CANoe 软件或者 CAPL 程序中调用这些 DLL,从而实现特定的功能。不同的总线类型,不同的协议类型,有不同的模型库,常用的总线标准库有 CANoeIL,OSEK NM, AUTOSAR NM,OSEK TP,SOME IP IL,DoIP等,本文主要讲述 OSEK TP 和 CANoeIL。


一、OSEK_TP.dll

在不用诊断描述文件的情况下,用户可以基于 CANoe 内置的 OSEK_TP.dll 动态链接库文件实现 CAN 诊断通信,该 DLL 内封装了大量的于 CAN 传输协议相关的函数。

1. 加载 OSEK_TP.dll 文件

用户可以在网络节点配置的 Components 选项中加载 OSEK_TP.dll 文件,如下:

常用的 dll 文件的路径,都在 CANoe 软件安装目录下的 Exec32 文件夹中,默认路径是:C:\Program Files\Vector CANoe 15\Exec32;

加载成功之后,能够在 CAPL Functions 窗口看到 osek_tp.dll 的函数库:

2. 常用函数介绍

long CanTpCreateConnection(dword addrMode):根据地址模式创建一个连接,如果入参是 0, 表示使用标准帧,如果入参是 1,表示使用扩展帧;

long CanTpSetRxIdentifier(long connHandle, dword rxID):设置用于接收协议数据消息的 CANID;

long CanTpSetTxIdentifier(long connHandle, dword txID):设置用于发送协议数据消息的CANID;

long CanTpSetMaxCANFDFrameLength(long connHandle, dword maxCANFDFrameLength):如果是 CANFD 总线,建立通信前调用这个函数,传入参数的最小值是 8,最大值是 64;

long CanTpSendData(long connHandle, byte txData[], dword txSize):发送诊断数据,如果接收到的 ECU 响应数据是多帧数据,接收到首帧之后就会自动发送流控帧。

示例代码:

variables { long dbHandle; } on key 'a' { byte txDataBuffer[8] = {0x19, 0x04, 0x00, 0x00, 0x01, 0x01}; long i; CanTpSendData(dbHandle, txDataBuffer, 6); } on start { initConn(0x613, 0x693); } void initConn(dword txId, dword rxId) { dbHandle = CanTpCreateConnection(0); // 0 表示标准帧, 1 表示扩展帧 CanTpSetTxIdentifier(dbHandle, txId); CanTpSetRxIdentifier(dbHandle, rxId); CanTpSetMaxCANFDFrameLength(dbHandle, 64); }

3. 回调函数介绍

用户在使用 OSEK_TP.dll 进行通信时,必须在 CAPL 程序中定义回调函数,来反馈发送诊断数据和接收数据。

void CanTp_ErrorInd(long connHandle, long error):连接发生错误时,触发该函数;

void CanTp_FirstFrameInd(long connHandle, dword length):诊断数据发送第一帧成功后,会调用该函数;

void CanTp_PreSend(long handle, word msgDLC[], byte data[]):在每次预定发送 CAN 消息时,都会调用该函数;

void CanTp_ReceptionInd(dword connHandle, dword count):诊断数据发送完毕且成功,会调用该函数;

void CanTp_TxTimeoutInd(long handle, word dlc[], byte msgData[]):如果 CAN 消息不能在超时时间 Ar 或 As 内发送,则调用该函数;

示例代码:

// 回调函数 void CanTp_SendCon(long connHandle, dword count) { write("Transmission of %d byte on connection %d successful", count, connHandle); }

4. 修改诊断字节未使用的默认值

long CanTpGetPadding(long connHandle):获取默认填充字节;

long CanTpSetPadding(long connHandle, long paddingValue):设置默认填充字节;

5. 修改流控帧参数

long CanTpSetBlockSize(long connHandle, dword blockSize):设置 BS 参数;

long CanTpSetSTmin(long connHandle, dword STmin):设置 STmin;

二、CANoeILNLVector.dll

DBC 文件中定义的报文和信号发送到总线(CAN Bus)之前,要经过交互层,用户通过 CAPL 程序对报文和信号进行读写操作,也需要经过交互层。因此用户可以通过交互层模型库 CANoeILNLVector.dll 观察总线上的数据变化,也可以根据需要控制报文的发送,修改信号数值,设置报文发送周期等。

1. 加载 CANoeILNLVector.dll 文件

如果在 DBC 文件中配置了 NodeLayerModules 为 CANoeILNLVector.dll,则可以在模块的 Components 看到自动加载的库文件:

2. IL 层控制函数

CANoeILNLVector.dll 中集合了丰富的函数,包括控制、故障注入、报文处理、信号处理等函数;

网络节点函数:

ILControlInit():初始化 IL 层,只能在 on preStart 中调用该函数,调用后周期报文发送停止,信号不可设置;

ILControlStart():报文开始周期发送,可设置信号值;

ILControlStop():报文停止周期发送,不可设置信号值;

ILControlWait():报文停止周期发送,可设置信号值;

ILControlResume():重新开始周期发送报文;

这些函数在哪个节点下,就控制哪个节点的报文,不需要传参;

on preStart { ILControlInit(); writeLineEx(-3, 0, "init IL layer, no message was sent."); } on key 'a' { ILControlStart(); writeLineEx(-3, 0, "start sending engine message."); } on key 'b' { ILControlStop(); writeLineEx(-3, 0, "stop sending engine message."); }

测试节点函数:

ILNodeControlStart():报文开始周期发送,可设置信号值;

ILNodeControlStop():报文停止周期发送,不可设置信号值;

ILNodeControlWait():报文停止周期发送,可设置信号值;

ILNodeControlResume():重新开始周期发送报文;

void MainTest() { writeLineEx(-3, 0, "ILNodeControlStop: stop light node message."); ILNodeControlStop("Light"); testWaitForTimeout(200); writeLineEx(-3, 0, "ILNodeControlStart: start light node message"); ILNodeControlStart("Light"); testWaitForTimeout(200); }

3. IL 层故障注入

网络节点函数:

long ILFaultInjectionDisableMsg(dbMsg msg):禁止发送报文;

long ILFaultInjectionEnableMsg(dbMsg msg):开始发送报文;

long ILFaultInjectionResetMsgCycleTime(dbMsg msg):重置报文周期为 DBC 中定义的值;

long ILFaultInjectionResetMsgDlc(dbMsg msg):重置报文 DLC 为 DBC 中定义的值;

long ILFaultInjectionSetMsgCycleTime(dbMsg msg, double value):设置报文周期;

long ILFaultInjectionSetMsgDlc(dbMsg msg, dword dlc):设置报文 DLC;

long ILFaultInjectionResetAllFaultInjections():重置所有的故障注入设置;

on key 'c' { writeLineEx(-3, 0, "stop sending message EngineState"); ILFaultInjectionDisableMsg(lookupMessage("EngineState")); } on key 'd' { writeLineEx(-3, 0, "start sending message EngineState"); ILFaultInjectionEnableMsg(lookupMessage("EngineState")); } on key 'e' { writeLineEx(-3, 0, "set message EngineState cycle time to 500ms"); ILFaultInjectionSetMsgCycleTime(lookupMessage("EngineState"), 500); } on key 'f' { writeLineEx(-3, 0, "reset message EngineState cycle time to 100ms"); ILFaultInjectionResetMsgCycleTime(lookupMessage("EngineState")); } on key 'g' { writeLineEx(-3, 0, "set message EngineState dlc to 8"); ILFaultInjectionSetMsgDlc(lookupMessage("EngineState"), 8); } on key 'h' { writeLineEx(-3, 0, "reset message EngineState dlc to 2"); ILFaultInjectionResetMsgDlc(lookupMessage("EngineState")); } on key 'i' { writeLineEx(-3, 0, "reset all fault injection conditions"); ILFaultInjectionResetAllFaultInjections(); }

测试节点函数:

long TestDisableMsg(dbMsg msg):禁止发送报文;

long TestEnableMsg(dbMsg msg):开始发送报文;

long TestResetMsgCycleTime(dbMsg msg):重置报文周期为 DBC 中定义的值;

long TestResetMsgDlc(dbMsg msg):重置报文 DLC 为 DBC 中定义的值;

long TestSetMsgCycleTime(dbMsg msg, float newCycleTime):设置报文周期;

long TestSetMsgDlc(dbMsg msg, dword dlc):设置报文 DLC;

long TestResetAllFaultInjections(dbNode aNode):重置所有的故障注入设置;

testcase case2() { writeLineEx(-3, 0, "stop sending message EngineState"); testDisableMsg(lookupMessage("EngineState")); testWaitForTimeout(1000); writeLineEx(-3, 0, "start sending message EngineState"); testEnableMsg(lookupMessage("EngineState")); testWaitForTimeout(1000); writeLineEx(-3, 0, "set message EngineState cycle time to 500ms"); testSetMsgCycleTime(lookupMessage("EngineState"), 500); testWaitForTimeout(1000); writeLineEx(-3, 0, "reset message EngineState cycle time to 100ms"); testResetMsgCycleTime(lookupMessage("EngineState")); testWaitForTimeout(1000); writeLineEx(-3, 0, "set message EngineState dlc to 8"); testSetMsgDlc(lookupMessage("EngineState"), 8); testWaitForTimeout(1000); writeLineEx(-3, 0, "reset message EngineState dlc to 2"); testResetMsgDlc(lookupMessage("EngineState")); testWaitForTimeout(1000); writeLineEx(-3, 0, "reset all fault injection conditions"); testResetAllFaultInjections(lookupNode("Engine")); testWaitForTimeout(1000); }

4. 仿真 Counter 和 CRC

CAN 总线上,两个节点通信,假设 A 节点给 B 节点发送一帧重要的报文,除了必要的信号数据,还会发送 Counter 和 CRC 信号。B 节点会根据约定的加密算法计算 CRC 和 Counter,并且与接收到的值进行比对,如果比对失败,则认为 A 节点发送的信号被篡改,将会上报故障。

1. applILTxPending 函数

CANoe 会根据 DBC 的定义,按照默认值发送仿真报文。仿真报文被发送到总线之前会经过回调函数 applILTxPending,用户可以在这个函数中计算报文的 CRC 和 Counter,然后将报文发送到总线上。

回调函数的实现思路:

根据定义好的算法,计算 Counter 和 CRC,将 计算好的值填充到报文的指定位置;

dword applILTxPending(long aId, dword aDlc, byte data[]) { if(aId == 0x100) { byte payload[64]; int i; byte tempCounter; tempCounter = data[1] & 0x0F; // 假设第1字节的低4位表示 counter 信号 tempCounter = (tempCounter + 1) % 16; data[1] = (data[1] & 0xF0) | tempCounter; for(i = 1; i < aDlc; i++) // 假设第0字节表示CRC { payload[i - 1] = data[i]; } data[0] = crc8(payload, aDlc - 1); } return 1; }

下面提供一种 CRC 的实现方式,具体的实现方式需要结合企业中实际的定义:

byte crc8(byte data[], long length) { byte tCRC; long i, j; tCRC = 0xFF; for(i = 0; i < length; i++) { tCRC ^= data[i]; for(j = 0; j < 8; j++) { if((tCRC & 0x80) != 0) { tCRC <<= 1; tCRC ^= 0x1D; } else { tCRC <<= 1; } } } return ~tCRC; }

2. 定时器实现

实现思路:

先初始化报文的 ID,channel等,再使用定时器持续发送报文。发送之前根据约定好的算法,先计算 counter 和 CRC,再填充到报文的指定位置,最后发送报文。

因为 CAPL 中定义的变量都是静态变量,因此每次发送之后变量的值都会保持上次值,而不需要通过回调函数获取到上次发送的值,因此能够实现。

variables { msTimer msgTimer; byte counter; dword msgId; byte channel; } on key '1' { msgId = 0x100; channel = 1; setTimerCyclic(msgTimer, 500); } on timer msgTimer { byte i; message * msg; byte simMsg[8]; msg.id = msgId; msg.can = channel; msg.DataLength = 8; msg.FDF = 0; counter = (counter + 1) % 16; simMsg[0] = counter; msg.byte(1) = counter; msg.byte(0) = crc8(simMsg, 7); output(msg); }

总结

本文介绍了 CANoe 两个常用模型库的用法:OSEK_TP.dll 用于在没有诊断描述文件时实现 CAN 诊断通信,核心是建立连接、设置收发 ID 并发送数据,同时实现必要的回调函数;CANoeILNLVector.dll 工作在交互层,可用于控制报文发送、注入故障,并通过applILTxPending回调或定时器仿真 Counter 和 CRC。

掌握这两个库的函数与回调机制,即可快速搭建 CAN 诊断通信与交互层仿真测试环境。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 1:53:23

LangChain 入门与实战

一、引言 大语言模型正在改变应用开发的方式&#xff0c;但很多开发者真正面对的问题并不是“模型不够强”&#xff0c;而是&#xff1a;如何把模型、数据、工具、记忆和业务流程可靠地连接起来。 如果只是简单调用一次模型&#xff0c;它往往只能输出一段文本&#xff1b;而一…

作者头像 李华
网站建设 2026/10/27 1:52:32

图文混排检索实战:图片怎么进向量库、怎么被检索到

个人主页&#xff1a;> for_ever_love__ <&#xff08;欢迎各位大佬莅临&#x1f60a;&#xff09; 其他栏目: > 大模型开发从0到1 < 其他栏目: > iOS项目总结大全 < 其他栏目: > 我想学python了 < 其他栏目: > iOS UI < 文章目录图文混排检索实…

作者头像 李华
网站建设 2026/10/27 1:51:19

Files 文件管理器使用指南:5 分钟上手多标签、分屏与文件标签

Files 文件管理器使用指南&#xff1a;5 分钟上手多标签、分屏与文件标签 【免费下载链接】Files A modern file manager that helps users organize their files and folders. 项目地址: https://gitcode.com/gh_mirrors/fi/Files 你是不是也被 Windows 自带资源管理器…

作者头像 李华
网站建设 2026/10/27 1:51:02

艾尔登法环存档编辑速查:调属性、加装备、修坏档都能做

艾尔登法环存档编辑速查&#xff1a;调属性、加装备、修坏档都能做 【免费下载链接】ER-Save-Editor Elden Ring Save Editor. Compatible with PC and Playstation saves. 项目地址: https://gitcode.com/GitHub_Trending/er/ER-Save-Editor ER-Save-Editor 是一个图形…

作者头像 李华