4. 诊断会话控制切换

任务目标

编写CAPL脚本,通过诊断仪向ECU发送会话控制请求,实现默认会话、编程会话和扩展会话之间的切换,并通过读取当前会话ID验证切换是否成功。

实现原理

诊断会话控制服务(UDS 0x10)通过子功能参数指定目标会话:0x01为默认会话,0x02为编程会话,0x03为扩展会话。ECU成功切换后返回肯定响应(0x50+子功能)。验证方式为发送读取当前会话ID的请求(UDS 0x22,DID 0xF199),从响应数据中解析会话ID。

关键完整代码

/* 诊断会话控制切换 - CAPL实现 */
variables
{
  const int DIAG_REQ_ID = 0x7E0;   // 物理请求ID
  const int DIAG_RES_ID = 0x7E8;   // 物理响应ID
  const int SESSION_DID  = 0xF199; // 会话ID DID

  diagRequest DiagnosticSessionControl_Req;
  diagResponse DiagnosticSessionControl_Res;
  diagRequest ReadDataByIdentifier_Req;
  diagResponse ReadDataByIdentifier_Res;
}

/* 发送会话控制请求 */
void SendSessionControl(byte subFunction)
{
  DiagnosticSessionControl_Req.SetPhysicalRequest(DIAG_REQ_ID, DIAG_RES_ID);
  DiagnosticSessionControl_Req.SetService(0x10);
  DiagnosticSessionControl_Req.SetParameter("SubFunction", subFunction);
  DiagnosticSessionControl_Req.SendRequest();
}

/* 读取当前会话ID */
void ReadCurrentSession()
{
  ReadDataByIdentifier_Req.SetPhysicalRequest(DIAG_REQ_ID, DIAG_RES_ID);
  ReadDataByIdentifier_Req.SetService(0x22);
  ReadDataByIdentifier_Req.SetParameter("DID", SESSION_DID);
  ReadDataByIdentifier_Req.SendRequest();
}

/* 会话控制响应回调 */
on diagResponse DiagnosticSessionControl_Res
{
  if (this.GetResult() == 0)  // 0表示肯定响应
  {
    byte subFunc = this.GetParameter("SubFunction");
    write("会话切换成功,子功能: 0x%02x", subFunc);
    ReadCurrentSession();  // 切换后读取会话ID验证
  }
  else
  {
    write("会话切换失败,NRC: 0x%02x", this.GetResult());
  }
}

/* 读取会话ID响应回调 */
on diagResponse ReadDataByIdentifier_Res
{
  if (this.GetResult() == 0)
  {
    word sessionId = this.GetParameter("DIDData");
    write("当前会话ID: 0x%04x", sessionId);
    
    // 根据会话ID判断当前会话类型
    if (sessionId == 0x01)
      write("验证结果: 默认会话");
    else if (sessionId == 0x02)
      write("验证结果: 编程会话");
    else if (sessionId == 0x03)
      write("验证结果: 扩展会话");
    else
      write("验证结果: 未知会话");
  }
  else
  {
    write("读取会话ID失败,NRC: 0x%02x", this.GetResult());
  }
}

/* 测试主函数 - 依次切换三种会话 */
testcase SessionSwitchTest()
{
  write("=== 诊断会话控制切换测试开始 ===");
  
  // 1. 切换到编程会话
  write("--- 切换到编程会话 (0x02) ---");
  SendSessionControl(0x02);
  TestWaitForDiagResponse(DiagnosticSessionControl_Req, 1000);
  
  // 2. 切换到扩展会话
  write("--- 切换到扩展会话 (0x03) ---");
  SendSessionControl(0x03);
  TestWaitForDiagResponse(DiagnosticSessionControl_Req, 1000);
  
  // 3. 切换回默认会话
  write("--- 切换回默认会话 (0x01) ---");
  SendSessionControl(0x01);
  TestWaitForDiagResponse(DiagnosticSessionControl_Req, 1000);
  
  write("=== 诊断会话控制切换测试结束 ===");
}

运行与验证

运行步骤:

  1. 在CANoe中创建仿真工程,添加一个CAN通道,配置诊断通信参数(请求ID 0x7E0,响应ID 0x7E8);
  2. 将上述代码添加到CAPL测试节点中,关联到对应通道;
  3. 在测试模块中调用SessionSwitchTest()测试用例;
  4. 确保ECU(或仿真面板)已上电并处于可响应诊断请求的状态。

通过条件:

  • CAPL输出窗口依次显示“会话切换成功”且子功能值正确;
  • 每次切换后读取的会话ID与目标会话一致(0x01/0x02/0x03);
  • 最终回到默认会话,验证输出显示“默认会话”。

常见问题

  • 响应超时:检查物理请求ID和响应ID是否与ECU配置一致,确认CAN通信正常;
  • NRC 0x12(子功能不支持):确认ECU是否支持对应会话切换,部分ECU需先解锁安全等级才能进入编程会话;
  • 会话ID读取失败:确认DID 0xF199在目标ECU上有效,若使用其他DID需同步修改代码中的SESSION_DID常量。