CAPL学习-DOIP固有函数(测试仪端)

CAPL中DoIP测试函数详解

1 DoIP_SelectVehicle

CAPL 函数 » 诊断 » DoIP_SelectVehicle

1.1 注意

仅当测试程序使用内置 DoIP 通道时,这些函数才有效,即:如果测试程序使用 CAPL 回调接口(CCI),则它们无效。

1.2 函数

1.2.1 语法

long DoIP_SelectVehicle(byte EID[6]);
long DoIP_SelectVehicle(char VIN[]);

1.2.2 功能说明

指定测试设备应面向的车辆,即在车辆识别请求消息中指示,或选择一个响应的车辆进行通信。

  • 若在发送车辆识别请求(VIR)消息前调用此函数,它将在 VIR 消息中设置车辆识别号(VIN)或实体 ID(EID)。
  • 若在车辆识别阶段调用此函数,且已收到匹配车辆的车辆识别响应(或公告消息 VAM),则会选择该车辆。可从 DoIP_VehicleIdentificationCompleteInd 回调中调用此函数。

若要在 ECU 仿真中设置 VIN 和 EID,请使用 DoIP.DLL 函数 DoIP_SetEIDDoIP_SetVIN

1.2.3 参数

  • EID
    (6 字节)实体 ID,通常为以太网 MAC 地址。

  • VIN
    车辆识别号(17 个字符)。若传入空字符串,则发送不带参数的 VIR 消息。

1.2.4 返回值

错误代码

1.2.5 可用性

版本限制于测量设置限制于仿真/测试设置
8.1 SP2

1.3示例

TestCase TC_AccessVehicle1
{
  diagRequest ReadEcuInfo req;
  DiagSetTarget("ECU1");  // DoIP 描述
  // --- 通过 VIN 启动面向特定车辆的 VIR
  DoIP_SelectVehicle("VECT0RVEH1CLE0123");
  req.SendRequest();
  // 带 VIN 的 VIR 应快速响应
  TestWaitForDiagResponse(req, 1000);
  diagCloseChannel();  // 确保将发送另一个 VIR
  // --- 发送不指定车辆的 VIR
  DoIP_SelectVehicle("");  // 无参数 VIR 消息
  req.SendRequest();
  // 不带参数的 VIR 可能需要较长时间(包括重试)
  TestWaitForDiagResponse(req, 9000);
  diagCloseChannel();
}

2 TestWaitForDoIPActivationLineStartup

CAPL 函数 » 测试功能集 » TestWaitForDoIPActivationLineStartup

2.1函数

2.1.1 语法

long TestWaitForDoIPActivationLineStartup();

2.2.2 功能

等待测量开始后 DoIP 激活线(Activation Line)的启动时间结束。详情请参见《激活线(DoIP)》。

2.2.3 参数

2.2.4 返回值

  • 1:DoIP 激活线已激活配置时间,或未配置(无需等待)。
  • 其他值:错误代码。

2.2.5 可用性

  • 版本要求:9.0 SP3 及以上
  • 适用范围:测试节点
  • 测量设置:不支持
  • 仿真/测试设置:支持

2.3 示例

2.3.1 示例 1:确保测试用例中激活线启动时间已结束

// 若此测试用例首次运行,将观察激活线启动过程  
testcase ConnectToVehicle(char target[])  
{  
  TestWaitForDoIPActivationLineStartup(); // 启动时间后无操作  
  diagConnectChannel(target); // 带 target 参数的形式自 9.0 SP3 起可用  
}  

2.3.2 示例 2:在测试模块中确保启动时间已结束

// 确保测试模块或单元中启动时间已结束  
SafeDoIPSending(diagRequest * req)  
{  
  TestWaitForDoIPActivationLineStartup(); // 启动时间后无操作  
  req.SendRequest();  
}  

2.3.3 示例 3:通过系统变量显式禁用激活线以执行特定测试

testcase TC_CheckErrorWithoutActivationLine()  
{  
  char svActivationLine[100];       // 激活线系统变量名  
  char svActivationLineNS[100];     // 激活线系统变量命名空间  
  long activationLineDelay;         // 激活线延迟时间  

  // 获取激活线启动时间  
  activationLineDelay = diagGetCommParameter("DoIP.ActivationLineStartuptime");  

  // 若启动时间过短(<100ms),忽略测试  
  if (activationLineDelay < 100)  
  {  
    TestStepWarning("", "激活线启动时间 %d 过短,无法执行测试。已忽略。", activationLineDelay);  
    return;  
  }  

  // 确保实体有足够时间响应(测试启动前的状态)  
  diagCloseChannel();  
  testWaitForDiagChannelClosed(1000);  

  // 获取激活线系统变量信息  
  if (0 >= DiagGetCommParameter("DoIP.ActivationLineSysvar", 0, svActivationLine, elcount(svActivationLine))  
   || 0 >= DiagGetCommParameter("DoIP.ActivationLineSysvarNamespace", 0, svActivationLineNS, elcount(svActivationLineNS)))  
  {  
    TestStepFail("", "无法获取控制激活线的系统变量!");  
    return;  
  }  

  // 通过系统变量关闭激活线  
  TestStep("", "通过系统变量 %s::%s 关闭激活线", svActivationLineNS, svActivationLine);  
  sysSetVariableInt(svActivationLineNS, svActivationLine, 0);  
  TestWaitForTimeout(500); // 确保 DoIP 离线  

  // 通过系统变量开启激活线  
  TestStep("", "通过系统变量 %s::%s 开启激活线", svActivationLineNS, svActivationLine);  
  sysSetVariableInt(svActivationLineNS, svActivationLine, 1);  

  // 不给实体足够时间(启动时间未结束时测试)  
  TestStep("", "不给予实体足够响应时间");  
  TestWaitForTimeout(activationLineDelay - 100);  

  // 尝试连接车辆(预期失败,因启动时间未结束)  
  TestStep("", "尝试连接车辆 - 应失败(启动时间未结束)!");  
  diagConnectChannel();  

  // 检查连接超时结果  
  if (0 == testWaitForDiagChannelConnected(3000))  
  {  
    TestStepPass("", "激活线延迟结束前连接 DoIP 实体超时,符合预期");  
  }  
  else  
  {  
    TestStepFail("", "激活线延迟未结束时,连接 DoIP 实体未超时!");  
  }  
}  

3 激活线(DoIP)

CANoe 诊断 » 功能概述 » 基础 » 总线系统/协议 » DoIP » 激活线

从 CANoe 9.0 SP3 开始,DoIP 激活线可在测量开始时自动激活,并在测量结束时自动停用。激活线由一个可写入的长整型系统变量控制,其可能值为 0(未激活)和 1(激活)。

您可以通过 Vector I/O 配置对话框,为 Vector I/O 硬件自动配置合适的系统变量,例如 VN1630 或 VN1640 接口的标准 DOUT 端口。

如果配置中存在此类系统变量,您可以在 DoIP/HSFZ 主设置 页面选择它。测量开始时,该变量将被设为 1;测量结束时,将被设为 0。

当激活线已配置,且在测量开始后配置的延迟时间尚未结束前,从 DCW 或 FMW 发送诊断请求时,控制面板将显示以下错误:
DoIP 激活线启动时间未结束 - 请稍后重试。

在 CAPL 中,可通过函数 DiagGetCommParameter 及以下参数获取已配置的系统变量和延迟时间:

  • DoIP.ActivationLineStartuptime
  • DoIP.ActivationLineSysvar
  • DoIP.ActivationLineSysvarNamespace

在 CAPL 测试模块中,可调用函数 TestWaitForDoIPActivationLineStartup 确保已过配置的延迟时间。

4 返回值(诊断相关)

CAPL 函数 » 诊断 » 错误代码

可能返回的值:
返回值错误提示描述解决措施
0无错误,成功。--
>0数字,例如给定文本的长度。--
-100函数调用时提供的输入不一致或不充分。CAPL 函数调用的参数不可用。例如:参数值或字节位置超出范围。检查函数调用提供的参数。
-99对象的响应待处理,因此无法删除。诊断对象仍在使用中,因此操作无法执行。延迟操作,直到对象不再被访问。
-98句柄未分配给诊断对象。
遇到无效的诊断对象句柄!
未找到 ECU 限定符“…”的诊断描述!
引用的诊断对象不存在(或已不存在),或不存在具有给定限定符的目标。检查对象初始化是否成功(即 diagSetTarget 调用成功)。
确保对象在当前目标上下文中有效(例如,其声明的服务在目标描述中已定义)。
访问请求存储的最后一个响应时,确保请求已收到响应。
-97参数不存在于该对象中,或为常量。
未找到参数“…”或类型错误!
参数“…”被声明为常量!
访问复杂参数“…”时出错:子参数“…”未找到或为常量。
无法对参数执行操作,因为参数不存在或不可访问。确保参数存在于诊断对象中(某些原语可能根据数据包含不同参数)。
若参数在描述中声明为常量,则其值无法修改。
若参数类型不允许指定操作,将触发此错误。
-96函数未实现。调用的函数尚未实现。-
-95访问 CANdelaLib 时导致“…”错误(针对“…”)
参数或对象“…”未定义!
参数“…”的值转换失败:…
对诊断对象执行的操作与诊断描述中的定义冲突。警告详情将提供附加信息。
确保参数在访问的诊断对象中已定义。
确保为转换提供有效的符号/物理参数值。
-94节点未初始化诊断,即未调用 SetEcu/Target。
诊断未初始化!
测试工具必须调用 diagSetTarget()(例如)
未找到网络请求接口!
操作无法执行,因为测试工具尚未调用 diagSetTarget,或仿真节点未分配诊断描述(用于诊断服务器仿真)。确保 diagSetTarget 已调用并成功设置现有目标。
使用某些网络请求函数需选择网络描述。
为 ECU 仿真节点分配诊断描述。
-93未找到指定的回调函数。-有关 CAPL 回调接口的详细信息,请参见《诊断:通信层连接》。
-92传输协议(TP)层出错。传输协议层报告传输错误。在“Write”窗口中查看更多信息,在“Trace”窗口中检查通信序列是否存在问题。
-91一次只能发送一个请求/响应!一次只能发送一个诊断对象(即对象处理发送期间,无法发送其他对象)。确保前一个对象的处理已完成。
-90测试函数位于 TestCase 外部,或测试工具专用函数在 ECU 中调用(反之亦然)。某些功能仅在测试工具或测试模块的测试用例中可用。请求只能从配置为测试工具的节点发送(即 diagSetTarget 必须调用成功)。
响应只能从配置为诊断服务器仿真的节点发送(即必须分配诊断描述)。
TFS 功能仅在测试模块中可用(例如,使用 testWaitForDiagResponse 等待响应,或使用 testReportWriteDiagObject 将诊断对象写入测试报告)。
-89未指定种子和密钥库。
诊断配置中未指定 Seed & Key DLL。
-配置 Seed & Key DLL。
-88Seed & Key 库不包含匹配的 Seed & Key 函数。Seed & Key DLL 不包含合适的 Seed & Key 函数。配置包含预期 Seed & Key 函数的 DLL。详情参见《诊断会话控制基础》和《Seed & Key DLL / 安全访问》。
-87无法加载种子和密钥库。-确保配置正确的 Seed & Key 路径和文件名。
-86缓冲区太小。-增大缓冲区大小。
-85种子数组大小过大。-减小种子数组大小。
-84安全级别无效。-使用正确的安全级别。
-83变体无效。-使用受支持的变体。
-82发生未指定的错误。--
-81函数无法执行操作,因为硬件错误(例如,需要 K-Line 接口而非串行端口)。-确保硬件设备正确。
-80未找到匹配的请求以执行操作。例如,在 testReportWriteEcuInformation 期间未找到带常量参数的请求。-
-79未找到诊断通道。无法打开诊断通道。-
-78未找到合适的类或请求。-确保限定符在诊断描述中已定义。
-77发生超时。ECU 未对请求发送响应。-
-76传输失败。请求或响应无法发送。-
-75诊断描述中未找到该类。-确保类限定符在诊断描述中已定义。
-74诊断对象的 PDU 字节创建失败!可能需要设置无默认值的参数(例如)。无法为诊断 CAPL 对象创建字节序列,因此调用的 CAPL 函数无法工作(例如,无法在网络上发送请求)。确保对象中的所有参数(尤其是无默认值的必选参数)均设置为有效值。
检查诊断描述中相应的服务定义。
-73处理期间收到否定响应。-确保 ECU 正确响应。
-72无法计算密钥。-确保配置了正确的 Seed & Key DLL。
-71密钥未被接受。-确保配置了正确的 Seed & Key DLL。
-70诊断对象太小。
对象中不存在指定的元素。
-检查使用的索引。
注意

以下返回值请检查安全源和安全管理器配置:

返回值认证或授权结果
-199认证被拒绝
-198认证工具配置不当(例如,安全管理器不可用或通道未就绪)
-197此模式未实现
-196无效句柄
-195安全源错误
-194安全不可用
-193数据缺失
-192信号长度不匹配
-191一般错误
在多节点环境下,使用CAPL实现DOIP测试仪的并发通信可以通过以下几种方法: #### 多套接字方式 为每个DOIP节点创建独立的TCP套接字。这样每个套接字可以独立地与不同的节点进行通信,互不干扰。以下是示例代码: ```capl variables { int doipSocket1; int doipSocket2; byte rxData1[256]; byte rxData2[256]; dword rxLen1; dword rxLen2; } on start { // 创建第一个套接字并连接到节点1 doipSocket1 = socket_create(SOCKET_TYPE_TCP); if (doipSocket1 < 0) { write("Failed to create socket 1"); } else { if (socket_connect(doipSocket1, "192.168.1.100", 13400) != 0) { write("Failed to connect to node 1"); } else { write("Connected to node 1"); } } // 创建第二个套接字并连接到节点2 doipSocket2 = socket_create(SOCKET_TYPE_TCP); if (doipSocket2 < 0) { write("Failed to create socket 2"); } else { if (socket_connect(doipSocket2, "192.168.1.101", 13400) != 0) { write("Failed to connect to node 2"); } else { write("Connected to node 2"); } } } on timer doipTimer { // 向节点1发送数据 byte txData1[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; if (socket_send(doipSocket1, txData1, elcount(txData1)) < 0) { write("Failed to send data to node 1"); } // 向节点2发送数据 byte txData2[8] = {0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}; if (socket_send(doipSocket2, txData2, elcount(txData2)) < 0) { write("Failed to send data to node 2"); } } on socket receive doipSocket1 { rxLen1 = socket_recv(doipSocket1, rxData1, elcount(rxData1)); if (rxLen1 > 0) { // 处理从节点1接收到的数据 write("Received DOIP data from node 1"); } } on socket receive doipSocket2 { rxLen2 = socket_recv(doipSocket2, rxData2, elcount(rxData2)); if (rxLen2 > 0) { // 处理从节点2接收到的数据 write("Received DOIP data from node 2"); } } ``` #### 事件驱动方式 利用CAPL的事件机制,当有数据到达或者连接状态发生变化时触发相应的事件处理函数。这样可以高效地处理多个节点的并发通信,避免阻塞。例如: ```capl variables { int doipSockets[10]; byte rxData[10][256]; dword rxLen[10]; int numNodes = 2; } on start { for (int i = 0; i < numNodes; i++) { doipSockets[i] = socket_create(SOCKET_TYPE_TCP); if (doipSockets[i] < 0) { write("Failed to create socket for node %d", i); } else { char ip[20]; sprintf(ip, "192.168.1.%d", 100 + i); if (socket_connect(doipSockets[i], ip, 13400) != 0) { write("Failed to connect to node %d", i); } else { write("Connected to node %d", i); } } } } on timer doipTimer { for (int i = 0; i < numNodes; i++) { byte txData[8] = {i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8}; if (socket_send(doipSockets[i], txData, elcount(txData)) < 0) { write("Failed to send data to node %d", i); } } } on socket receive { for (int i = 0; i < numNodes; i++) { if (this == doipSockets[i]) { rxLen[i] = socket_recv(doipSockets[i], rxData[i], elcount(rxData[i])); if (rxLen[i] > 0) { // 处理从节点 i 接收到的数据 write("Received DOIP data from node %d", i); } } } } ``` #### 线程池方式(如果支持) 虽然CAPL本身没有直接的线程池概念,但可以通过合理的定时器和事件调度来模拟线程池的行为。将不同节点的通信任务分配到不同的“线程”(定时器或事件处理函数)中,实现并发处理。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

车载测试工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值