1 周期消息发送
无论是Simulation Setup中的仿真节点还是Test Setup中的Test Module所关联的CAPL脚本在做仿真或测试时都经常需要向总线模拟发送周期消息。
点击键盘按键 'a' 后向总线发送周期为20ms的can 消息msg:
variables
{
msTimer myTimer;
message 100 msg;
}
on key 'a' {
setTimer(myTimer,20);
}
on timer myTimer {
output(msg);
setTimer(myTimer,20);
}
2 应用报文REQUEST/RESPONSE测试
ECU通常都有很多请求/应答式的功能,比如BCM可以接收用户点击车窗、雨刮、遮阳帘等车身相关硬件的控制按钮向总线发出的开关请求(Request),然后由BCM向总线发出响应消息,并控制车窗、雨刮、遮阳帘等做出相应的反馈动作(Response)。
下面以测试BCM雨刮开关功能为例进行Request/Response测试。
DBC定义:
参考代码:
variables
{
message BCM_Request tBCM_Request;
message BCM_Response tBCM_Response;
int result = 0;
int waitTime = 1000;
}
void MainTest()
{
TestModuleTitle ("Test BCM Features");
TestModuleDescription ("Check all features in BCM.");
TestGroupBegin("BCM Wiper Feature", "Check the perfomance of Wiper");
Check_Wiper_Feature(0,0); //测试雨刮关闭功能
Check_Wiper_Feature(1,1); //测试雨刮开启功能
TestGroupEnd();
}
//Wiper Feature testcase
testcase Check_Wiper_Feature(int request, int response )
{
tBCM_Request.WiperRequest.phys = request;
output(tBCM_Request);
//测试请求发出去后1000ms内是否收到BCM的响应信号。
result = TestWaitForSignalMatch(BCM_Response::WiperResponse,response,waitTime);
passResult(result,request,response);
}
void passResult(long result,int request,int response)
{
switch(result){
case 1: TestStepPass("1.0","Test Pass - request : %d expect response : %d ",request,response);break;
case 0: TestStepFail("1.0","Timeout - request : %d expect response : %d ",request,response);break;
case -1: TestStepFail("1.0","General error - request : %d expect response : %d ",request,response);break;
case -2: TestStepFail("1.0","Signal is not valid");break;
default:break;
}
}
3 检测总线中周期报文的发送周期是否在给定范围内
TSL提供了两组函数用于测试周期报文:
一组使用相对时间因子,当周期小于 (aMinRelCycleTime * GenMsgCycleTime)或大于(aMaxRelCycleTime* GenMsgCycleTime)时产生事件。
函数原型:
dword ChkCreate_MsgRelCycleTimeViolation (Message aObservedMessage, double aMinRelCycleTime, double aMaxRelCycleTime, Callback aCallback);
dword ChkStart_MsgRelCycleTimeViolation (Message aObservedMessage, double aMinRelCycleTime, double aMaxRelCycleTime, Callback aCallback);
另一组使用绝对时间参数,当周期小于 aMinCycleTime 或大于 aMaxCycleTime 时产生事件。
dword ChkCreate_MsgAbsCycleTimeViolation (Message aObservedMessage, duration aMinCycleTime, duration aMaxCycleTime, char[] aCallback);
dword ChkStart_MsgAbsCycleTimeViolation (Message aObservedMessage, duration aMinCycleTime, duration aMaxCycleTime, char[] aCallback);
参考代码:
testcase CheckMsgEngineData()
{
float aMinRelCycleTime = 0.9;
float aMaxRelCycleTime = 1.1;
// Information for test report.
TestCaseTitle("TC 4", "Check cycle time of message EngineData");
// checks the cycle time of the message
gCycCheckId = ChkStart_MsgRelCycleTimeViolation (EngineData, aMinRelCycleTime , aMaxRelCycleTime );
TestAddCondition(gCycCheckId);
// sequence of different actions and waiting conditions
TestWaitForTimeout(1000);
TestRemoveCondition(gCycCheckId);
}
测试报告中设置的命令如下,请您自行查阅CANoe帮助文档,或者查找自带的模板。
TestModuleTitle ("Test BCM Features");\\测试报告标题。
TestModuleDescription ("Check all features in BCM.");\\测试报告描述。
输出的测试报告如下图所示:
如上图所示,测试报告展示了错误事件产生的次数以及错误事件所处的事件范围。
4 统一诊断测试(UDS)
诊断测试经常需要进行切换session,22/2E读写等request/response式的操作,CANoe Demo工程UDSBasic.cfg中Simulation Setup窗口里的TestModule节点关联的CAPL脚本为我们提供了一个很好的参考模板:
参考代码:
/*@!Encoding:1252*/
// --------------------------------------------------
// Simple test module for automated tests.
// For the sake of simplicity, this example omits
// security access mechanisms, especially for the
// write services. In some cases, return parameters
// are not checked.
//
// CANoe 10.0 and higher
// --------------------------------------------------
includes
{
// As this is a test module, neither including the CAPL callback interface nor adding
// the corresponding transport protocol node layer DLL is necessary, because in this case,
// the "built-in" diagnostic channel of CANoe can be used.
}
variables
{
enum bool {true=1, false=0};
const cAccessModeNumerical=0;
const cAccessModePhysical=1;
const cAccessModeCoded=2;
const test_vehicle_Speed_kmh = 40.0;
// This timeout is used just to force CANoe to continue, i.e. normally a TestWaitForDiag...
// function will return much earlier due to diagnostic level timing!
const cApplicationTimeoutMs = 5000;
char gTestIdStr[10]; // Test step ID for test report
word gTestCaseIndex=0;
word gTestStepIndex=0;
char gResultString[200]; // String for temporary test step result outputs
}
// Set and increment test step ID for test report
updateTestIdStr()
{
snprintf(gTestIdStr, elcount(gTestIdStr), "%d.%d", gTestCaseIndex, gTestStepIndex);
}
setTestId(word tcIndex, word tsIndex)
{
gTestCaseIndex=tcIndex;
gTestStepIndex=tsIndex;
updateTestIdStr();
}
incTestStepId()
{
gTestStepIndex++;
updateTestIdStr();
}
word SendRequestAndWaitForResponse(diagRequest *req, enum bool posResponseExpected)
{
long ret;
// Trigger sending the request
if (0 > (ret=req.SendRequest())) {
snprintf(gResultString, elcount(gResultString), "Trigger sending the request failed (Return code=%d)!", ret);
testStepFail(gTestIdStr, gResultString);
return 0;
}
testStepPass(gTestIdStr, "Trigger sending the request succeded.");
incTestStepId();
// Wait until the complete request has been sent, e.g. in case of long requests which spread over several messages (segmented message)
if (1!=(ret=testWaitForDiagRequestSent(req, cApplicationTimeoutMs))){
snprintf(gResultString, elcount(gResultString), "Failed to finish sending the request (Return code=%d)!", ret);
testStepFail(gTestIdStr, gResultString);
return 0;
}
testStepPass(gTestIdStr, "Request was sent successfully.");
incTestStepId();
// Wait until the complete response has been received, e.g. segmented messages might take some time for transmission
if (1!=(ret=testWaitForDiagResponse(req, cApplicationTimeoutMs))) {
snprintf(gResultString, elcount(gResultString), "Valid response missing or received too late (Return code=%d)!", ret);
testStepFail(gTestIdStr, gResultString);
return 0;
}
testStepPass(gTestIdStr, "Response received successfully.");
incTestStepId();
// Check whether the response was a positive response
if (-1==(ret=diagGetLastResponseCode(req))) {
if (!posResponseExpected) {
snprintf(gResultString, elcount(gResultString), "Positive response received although negative response was expected!");
testStepFail(gTestIdStr, gResultString);
return 0;
}
testStepPass(gTestIdStr, "Positive Response received as expected.");
}
else if (ret>0) {
if (posResponseExpected) {
snprintf(gResultString, elcount(gResultString), "Negative response received (NRC=0x%02x) although positive response was expected!", ret);
testStepFail(gTestIdStr, gResultString);
return 0;
}
testStepPass(gTestIdStr, "Negative Response received as expected (NRC=%d).", ret);
}
return 1;
}
// Check whether writing the vehicle speed parameter is done correctly by reading its value after writing
testcase tcWriteAndReadVehicleSpeed()
{
diagRequest Door.Variant_Coding_Write req_write;
diagRequest Door.Variant_Coding_Read req_read;
double ret;
word testCaseIndex;
setTestId(1,1);
TestStep(gTestIdStr, "Writing variant coding");
if (0>req_write.SetParameter(cAccessModePhysical, "Codingstring.VehicleSpeedToLockDoor", test_vehicle_Speed_kmh)) {
testStepFail(gTestIdStr, "Could not set parameter 'VehicleSpeedToLockDoor' in write request!");
}
else {
if (0>req_write.SetParameter("Codingstring.VehicleType", "Sedan")) {
testStepFail(gTestIdStr, "Could not set parameter 'VehicleType' in write request!");
}
else {
sendRequestAndWaitForResponse(req_write, true);
}
}
incTestStepId();
TestStep(gTestIdStr, "Reading variant coding");
if (sendRequestAndWaitForResponse(req_read, true)) {
incTestStepId();
ret=req_read.GetRespParameter(cAccessModePhysical, "Codingstring.VehicleSpeedToLockDoor");
if (test_vehicle_Speed_kmh == ret) {
testStepPass(gTestIdStr, "VehicleSpeedToLockDoor read as expected!");
}
else {
testStepFail(gTestIdStr, "Read VehicleSpeedToLockDoor value is wrong (value=%f)!", ret);
}
}
}
void MainTest ()
{
tcWriteAndReadVehicleSpeed();
}
CANoe提供的Demo工程是学习CANoe最好的资源,熟悉以上示例代码已经能够帮助我们开发出大部分诊断测试case。
版权声明:本文为haokeyu1752558508原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。