<CANoe_C#> Programming with the CANoe .NET API

3 篇文章 3 订阅
这篇博客详细介绍了CANoe中的常见特性,包括信号处理、消息构造、计时器应用和事件处理程序。内容涵盖了如何设置信号值、处理数组型环境变量、构建用户定义的CAN消息、使用计时器以及定义各种事件处理程序,如onChange、onCANFrame、onKey等。此外,还涉及了测试特性,如测试模块类型、报告命令、等待点、检查和准则,以及诊断测试的实现。最后,提到了调试.NET程序的方法和故障排查技巧。
摘要由CSDN通过智能技术生成


1. Common Features

1.1 Signals (bus signals, environment and system variables)

NET中的信号类型通常是指总线信号、环境变量和系统变量。这些类型的处理方式完全相同。

1.1.1 设置信号值

//Signal values can be accessed through the Value property, e.g. <signal name>.Value.
LockState.Value = 1;

1.1.2 数组类型的环境变量

如果环境变量是数据数组类型,则可以使用索引运算符轻松读取每个字节:

if (MyDataEv.Value[2] == 2) {}

赋值时,需要按以下步骤进行:

Byte[] tmp = MyDataEv.Value;
tmp[2] = 2;
MyDataEv.Value = tmp;

当信号对象的名称已知时,还可以动态创建它。下面是一个示例,如何创建系统变量对象(namespace = ‘Tester’ and variable name = ‘Enabled’),并修改其值:

DynamicSystemVariable var = new DynamicSystemVariable("Tester", "Enabled");
var.Value = 1;

1.2 Message

为了构造数据库(例如dbc)中未定义的用户定义的CAN消息,可以将CANFrame类用作一个父类。信号用[Signal]属性定义。

class myMessage : CANFrame
{
[Signal(LSB = 0, BitCount = 2)]
public UInt32 mySignal;
}
myMessage msg = new myMessage(0x42,8);
msg.Send();

CAN消息也可以通过创建CANFrame类的实例并在构造函数中初始化ID和DLC来声明。只能以原始格式设置消息数据,可以使用属性Bytes[]按字节设置,也可以通过大小必须为8 Bytes min的字节数组设置:

byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
CANFrame msg = new CANFrame(0x500, 4); // ID=0x500, DLC=4
msg.SetRawData(data);
msg.Send();

1.2 Timer

属性[OnTimer]可用于完成循环计时器。该方法将在定义的时间点(这里是1s)循环执行。
对于测试模块,当测试模块处于活动状态时,计时器处于活动状态;对于模拟节点,在测量过程中,计时器处于活动状态。

[OnTimer(1000))]
public void OnTimer1s() {
Output.Writeline("Timer elapsed");
}

如果计时器应该在某个点启动和停止,则可以使用计时器对象。使用Timer类及其属性/方法,例如定义计时器处理程序:

{
Timer t = new Timer(new TimeSpan(0, 0, 0, 0, 250),TimerHandler);
t.Start();
…
t.Stop();
}
public void TimerHandler(Object o, ElapsedEventArgs e)
{
Report.TestCaseComment("Timer event");
}

1.3 Event Procedures

对于测试模块,当测试模块处于活动状态时,事件处理程序处于活动状态;对于模拟节点,事件处理程序在测量期间处于活动状态。

1.3.1 OnChange

对网络信号LockState的值变化作出反应的处理程序定义如下:

[OnChange(typeof(LockState))]
public void OnSignalLockState() {
double value = LockState.Value;
}

面向信号的.NET API只支持“on change”处理程序,而CAPL同时支持“on change”和“on update”处理程序。一个原因是.NET程序的性能方面。另一个原因是基于信号的测试是基于状态的。
与此相反,消息处理程序(7.1版引入)是基于事件的。要处理消息窗口状态的消息事件,请使用[OnCANFrame]属性。CAN通道和消息ID也可以在属性构造函数中指定。

1.3.2 OnCANFrame

[OnCANFrame]
public void onMessage(NetworkDB.Frames.WindowState frame) {
double pos = frame.WindowPosition.Value;
}


[OnCANFrame(1, 500)]
public void Frame500Received(CANFrame frame) {}

1.3.3 OnKey

使用属性[OnKey]对关键事件作出反应。定义的方法必须有一个char参数。

[OnKey('+'))]
public void OnKeyPressed(char ch) {
Output.WriteLine("+ was pressed");
}

1.3.4 OnTimer

要处理计时器事件,应该使用[OnTimer]属性。每500毫秒调用一次下面的TimeRecursed方法:

[OnTimer(500))]
public void TimerElapsed() {
msg.Send();
}

1.3.5 OnChange

该模块还可以对系统变量变化作出反应:

[OnChange(typeof(MyNameSpace.MyInt))]
public void MyIntHandler()
{
MyNameSpace.MyInt2.Value = MyNameSpace.MyInt.Value;
}

2 Test Features

2.1 Test Module Types

有两种不同类型的测试模块:

1 非结构化测试模块-Unstructured test modules
在测试模块执行期间,将显示并完成测试用例和组的顺序。不可能启用单个测试用例或组。
2 结构化测试模块-Structured test modules
与非结构化模块相比,这些模块具有很大的优势,因为它们的结构在编译之后直接显示在测试执行对话框中,并且可以在测试执行之前启用或禁用它们。

2.1.1 Unstructured test modules

非结构化.NET测试模块必须从类Vector.CANoe.TFS.TestModule继承。它主要由执行测试控制流和测试用例的主要方法组成。测试组可以用来组织属于一起的测试用例。测试用例是用自定义属性[TestCase]定义的,可以分为几个测试步骤。Vector.CANoe.TFS.Report类用于向报告文件报告。
测试模块的主要方法是将测试模块的主程序模拟成CAPL测试模块。重写TestModule类继承的Main方法是必需的。主方法将测试用例分组并按顺序执行它们:

public class MyTestModule : TestModule
{
public override void Main()
{
TestGroupBegin("Id", "Title", "Description");
TestCase1();
if (TestModule.VerdictLastTestCase == Verdict.Passed)
{
TestCase2();
}
TestCase3();
TestGroupEnd();
}
}
[TestCase("Test case title")]
public void TestCase1()
{
Report.TestStep("Description of the test step");
}

主方法应该只包含测试流控制。具体的测试应该在测试用例中进行。可以实现复杂的流逻辑,例如,让一个测试用例通过在循环中调用它来执行多次,或者在前面的测试用例返回失败时阻止执行测试用例。
一般来说,测试用例的编程应该使它们不相互依赖,例如在测试用例之间不使用全局变量。建议重新开始每个测试用例;

在测试用例开始前初始化参数,如果需要,在测试用例结束后重置参数。这确保了良好的编程实践和可能的代码重用(这是.NET API的主要动机之一)。
事件程序仅在测试模块运行期间有效,因为测试模块不必在整个测量期间始终有效。

2.1.2 Structured test modules

结构化.NET测试模块必须从类Vector.CANoe.TFS.StructuredTestModule继承。测试模块的StructuredMain方法是主程序,需要重写StructuredTestModule类继承的StructuredMain方法。需要动态测试序列(两个测试模块之间可能不同的测试序列运行)使用标记有[TestGroup]属性的方法进行封装。动态测试组将始终作为一个整体执行。
该示例显示了一个DynamicTestGroup()和一个包含两个测试用例的普通测试组。

public class MyTestModule : StructuredTestModule
{
public override void StructuredMain()
{
DynamicTestGroup();
TestGroupBegin("Id", "Title", "Description");
TestCase1();
TestCase3();
TestGroupEnd(); }
}
[TestCase("Test case title")]
public void TestCase1()
{
Report.TestStep("Description of the test step");
}[TestGroup(Dynamic Test case sequence”,” depends on preceding test case results”)]
public void DynamicTestGroup()
{
TestCase1();
if (TestModule.VerdictLastTestCase == Verdict.Passed)
{
TestCase2();
// …
}
}

StructuredMain方法只能定义测试序列。具体的测试应该在测试用例和测试组中进行。
事件过程仅在测试模块执行期间处于活动状态

2.2 Reporting Commands

report类允许详细报告测试结果和测试执行步骤。这里列出了最重要的方法。
在这里插入图片描述

2.3 Wait Points

通常情况下,SUT的刺激是在测试用例中生成的,然后等待反应。测试模块的顺序执行可以被所谓的等待点中断。等待点的原理是,它们将流控制返回到CANoe,直到指定的事件发生(例如,信号值更改、消息接收或超时)才恢复处理。

对于简单超时、总线或I/O信号的专用值、消息、用户定义(复杂)系统条件的实现、用户交互等,都有等待点。通过使用执行类的wait方法来完成等待点:

//Simple timeout: 
Execution.Wait(50);
//Bus signal: 
Execution.Wait<EngineRunning>(1);
//System variable: 
Execution.Wait<SystemUnderTest.OperationMode>(2);
//Environment variable: 
Execution.Wait<EnvDoorLocked>(EnvDoorLocked.Locked);
//Message: 
Execution.WaitForCANFrame(ref frame, 500);

NET中面向信号的API是面向状态的。这意味着,如果使用信号元素的等待点,则立即检查等待条件,如果信号已设置(即满足条件),则等待点也会立即恢复。与.NET面向消息的方法中的面向信号的方法不同,面向消息的方法是基于事件的。

2.4 Checks

NET测试模块中的Checks用于在测试序列期间监视某些系统状况。
有三种类型的检查;约束、条件和观察

约束用于保证环境满足某些标准和条件,并监督被测系统的行为。任何违反这些检查的行为都会导致测试用例和测试模块失败。
这与不能影响测试模块判断的观察结果形成对比,即使测试报告中总是包含违规行为。
检查可以在一个完整的测试序列、一个完整的测试用例中激活,也可以是
使用方法调用激活/停用。

TFS提供了几个预定义的检查
在这里插入图片描述
自定义Checks:
在这里插入图片描述
类ValueCheck表示对信号、环境变量或系统变量的值的简单检查。这里检查引擎信号值:

[TestCase("Title", "Description")]
public void ObserveEngineState()
{
ICheck engOn = new ValueCheck<EngineRunning>(CheckType.Observation, 1);
engOn.Activate();
Vector.CANoe.Threading.Execution.Wait(4000); // observation active
engOn.Deactivate();
}

这是检查总线信号值的示例。首先,使用值“1”的类型条件创建对信号值的检查。然后检查被激活,在等待4s之后,检查在测试用例结束之前被停用。
消息的周期时间检查是这样完成的。激活操作如前一个示例所示。

ICheck check = new AbsoluteCycleTimeCheck<NetworkDB.Frames.CyclicMsg>
(CheckType.Condition, 80, 120);

如果应检查用户定义的系统条件,则可以定义自定义类(例如,对于DLC
观察结果):

{
public MyUserCheck(string title, string description)
: base(title, description)
{}
[OnCANFrame(1, 0x64)]
public void FrameReceived1(CANFrame frame)
{
if (frame.DLC != 1)
ReportViolation("DLC check for frame 0x64 failed");
}
}

Checks的应用如上所述:

ICheck check = new MyUserCheck("MyUser check", "Check DLC of message 0x64");
check.Activate(); // or: check.Activate("a new title");
// ...
check.Deactivate();

用户检查可以组合多个运行时值作为验证条件。

2.5 Criterions

在这里插入图片描述

Criteria属性可用于定义要在检查点或等待点中使用的处理程序

[Criterion]
[OnChange(typeof(AntiTheftSystemActive))]
[OnChange(typeof(LockState))]
bool AntiTheftSystemCriterion()
{
if((EngineRunning.Value == 0) && (LockState.Value == 1))
return (AntiTheftSystemActive.Value == 1);
else
return (AntiTheftSystemActive.Value == 0);
}

在检查中应用上述条件–如果条件处理程序返回false,则检查失败:

Check observeAntiTheftSystem = new Check(AntiTheftSystemCriterion);
observeAntiTheftSystem.Activate();

在Wait Point条件中应用上述条件–如果条件处理程序返回true,则恢复等待点:

Execution.Wait(AntiTheftSystemCriterion);

注1:在设置等待或检查时立即调用处理程序来处理启动条件。
注2:仅当check或wait条件处于活动状态时,用criteria属性标记的处理程序才处于活动状态。

criteria类可用于将多个单一准则组合为一个复杂准则,例如,当必须并行检查多个信号值时。这类似于CAPL中的 testJoinAuxEvent() 函数。

Criterion antiTheftSystem = new Criterion();
antiTheftSystem.AddMandatory(new ValueCriterion<AntiTheftSystemActive >(0));
antiTheftSystem.AddOneOf(new ValueCriterion<LockState>(0));
antiTheftSystem.AddOneOf(new ValueCriterion<EngineRunning>(1));

同样,组合标准可用于检查-如果违反强制性条件或违反所有可选条件,则检查失败:

Check observeAntiTheftSystem = new Check(antiTheftSystem);
observeAntiTheftSystem.Activate();

2.6 User Dialogs

原始的windows对话框不能在.NET测试模块中使用,因为它们会干扰CANoe的实时行为。相反,Vector.CANoe.Threading和Vector.Scripting.UI中有几个预定义的对话框。下面是一些如何使用它们的例子。

Tester Confirmation Dialog:

int result = Execution.WaitForConfirmation("Please confirm!");
//or
int result = ConfirmationDialog.Show(("Please confirm!","Confirmation Dialog");

Value input with ranges:

List<Range<uint>> l = new List<Range<uint>>();
l.Add(new Range<uint>(1, 5));
l.Add(new Range<uint>(10, 15));
RangeCollection<uint> mRangesUint = new RangeCollection<uint>(l);
result = DataEntryDialog.Show<uint>(
"Please enter a value between 1-5 or 10-15! ",
"ValueInput with range",
"Two different ranges are defined.", ref value, mRangesUint);

2.7 Test Patterns

测试模式是基本的预定义测试过程或测试流,可以用值参数化,并在测试用例中执行。通常,模式用输入值参数化,超时后检查输出(预期)值。测试模式的使用是
支持重用概念。
在.NET中,测试模式被实现为抽象类,例如类StateChange。这些抽象类必须实例化为具有类型化输入和输出(预期)向量的具体类。StateChange模式实现了典型的流:stimulate、wait、evaluate——也可以从XML测试模块模式中得知。自定义属性[Input]和[Expected]用于确定输入(刺激)和输出(评估)参数。
首先通过从抽象类派生来创建测试模式。定义超时、输入和期望值。

public class CrashDetectionTest : StateChange
{
public CrashDetectionTest() { Wait = 200; }
[Input(typeof(NetworkDB.CrashDetected))]
public double crashDetected = 1;
[Expected(typeof(NetworkDB.LockState), Relation.Equal)]
public double lockState = 0;
}

创建的测试模式现在可以在测试用例中使用,例如通过对其应用Execute()方法:

[TestCase]
public void LockStateDependsOnCrashDetection()
{
// Test Pattern - Crash Detection function test
CrashDetectionTest crashTest = new CrashDetectionTest();
crashTest.Execute();
// Change test pattern input parameter and re-execute
crashTest.crashDetected = 0;
crashTest.Execute();
}

可以使用[TestFunction]属性定义用户定义的测试模式:

[TestFunction]
private void InitSUT()
{
// perform some actions
}

执行测试功能时,详细的报告数据会写入测试报告。

2.8 Diagnostic Tests

诊断用于实现诊断请求/响应场景。一个简短的例子说明了这一点:

[TestCase("Diagnostic Test")]
public void TC_Diagnostic()
{
    // select a diagnostic target ECU:
    Ecu myEcu = Application.GetEcu("ECU");
    // Create a request
    Request request = myEcu.CreateRequest("ECUOrgin_Read");
    // Send the request and wait for a response
    SendResult result = request.Send();
    // Check if the message transmission was successful
    if (result.Status == SendStatus.Ok)
    {
        // Get the response (Caution: the response might be null)
        Response response = result.Response;
        // Check if the ECU sent a positive response
        if (response.IsPositive)
        {
            Report.TestStepPass("Pos response received.");
            // Read and verify a parameter value:
            Parameter para = response.GetParameter("SerialNumber");
            if (para.Value.ToInt32 == 123)
                Report.TestStepPass("Serial number is OK");
            else
...
        }
        else
        {
            Report.TestStepFail("Negative Response received");
        }
    }
    else
    {
        Report.TestStepFail("Sending failed." + result.Status.ToString());
    }
}

服务和参数限定符可以从CANoe符号资源管理器中复制。
更多的背景信息可以在“VDS\u Library\u QuickStart.pdf”中找到,该文件位于CANoes开始菜单/Help/“Documentation Vector Diagnostic Scripting Library”中。

3 Debugging .NET Programs

所有.NET程序都在CANoe实时任务“RuntimeKernel.exe”中执行。要调试.NET程序,调试器必须附加到RuntimeKernel.exe,并带有“managed code type”选项。首次启动CANoe测量时,将启动runtimekernel.exe。
在这里插入图片描述
当.NET模块是用CANoe生成的时,通常没有可用的调试信息,您应该首先在IDE中用启用的调试模式重新生成程序集,或者可以在“选项”对话框(菜单:配置|选项|编程|.NET调试|.NET调试器)中的CANoe中启用.NET调试
如果您在CANoe的模拟模式下调试您的模块,那么在选项对话框(菜单:配置|选项|测量|常规|模拟|使用windows计时器)中启用“windows计时器”很有用。
有关如何附加调试器的详细信息,请参阅VisualStudio文档。

4 Troubleshooting

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

[TestClass]
public class TestCaseLibrary
{
    [Export]
    [TestCase]
    [BreakOnFail(true)]
    public static void TestWithOwnExceptionHandling()
    {
        try
        {
		//Do something you need exception handling}
	    catch (MyConcreteException)
        {
		//Do something inside your catch-block}
    }
    //Override the “System.Exception”-class
    private class MyConcreteException : System.Exception { }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值