CAPL Script

CAPL 的 Debug

先核对结论,再调试代码

“速度没有超过阈值,却出现了告警”还没有确定发送者或触发条件。本篇设置两个合法告警来源,演示如何区分比较错误与对正确事件的不完整解释。

在隔离的 CAN1 配置中使用一个 Simulation Setup 节点,为练习保留经典 CAN 标准 ID 0x220。模型不依赖 DBC 或实物硬件;数值特意命名为 raw,不表示 rpm 或摄氏度。以下教学代码尚未在本站编译运行,应先用安装版 CANoe 编译器与帮助核实。

一个可重复场景,两个可能来源

variables
{
  long speedRaw;
  long temperatureRaw;
  long alarmRequests;
  message CAN1.0x220 alarm;
}

void requestAlarm(byte reason)
{
  alarm.RTR = 0;
  alarm.DLC = 1;
  alarm.byte(0) = reason;
  alarmRequests++;
  write("[Alarm] request=%d reason=%d speedRaw=%d temperatureRaw=%d",
        alarmRequests, reason, speedRaw, temperatureRaw);
  output(alarm);
}

on start
{
  speedRaw = 0;
  temperatureRaw = 0;
  alarmRequests = 0;
}

on key 's'
{
  speedRaw = 3200;
  write("[SpeedCheck] raw=%d hex=0x%X threshold=5000",
        speedRaw, speedRaw);
  if (speedRaw > 5000) requestAlarm(1);
}

on key 'h'
{
  speedRaw = 6000;
  write("[SpeedCheck] raw=%d threshold=5000", speedRaw);
  if (speedRaw > 5000) requestAlarm(1);
}

on key 't'
{
  temperatureRaw = 110;
  write("[TemperatureCheck] raw=%d threshold=100", temperatureRaw);
  if (temperatureRaw > 100) requestAlarm(2);
}

启动测量,先按 s 再按 t。待验证预期是先记录速度检查值 3200,再发出原因 2 的温度告警。速度条件为假,温度条件为真,两者没有矛盾。这些是由代码推导的预期,不是已采集日志。

重新启动后的输入 预期请求计数 发生请求时的载荷
s 0 不请求发送
h 1 01:速度来源
t 1 02:温度来源
s 后接 t 1 02,即使记录的速度较低

单字节原因码是本教学协议的一部分,让接收者能观察到具体路径。只写在发送端日志中的来源标签,无法从内容完全相同的总线帧中反推出。

沿四个观察点追查证据

  1. **输入:**确认按键事件及赋值。如果实际工程改为 CAN 输入,先检查通道、方向、ID、帧类型和 DLC,再读取载荷。
  2. **决策:**断点放在比较表达式处、条件调用之前。只在条件内部放断点,条件为假时不会触发,也解释不了另一个处理器的活动。
  3. **请求:**在 output 前检查 reason、alarmRequests 和载荷。搜索整个配置中所有 0x220 发送者;单个源文件不等于整个工程。
  4. **观察:**分别查看 Trace 和接收端。请求计数只证明本节点调用次数,不证明交付成功。关闭其他发送者,用通道、ID、载荷与时间建立对应关系。

调试菜单和快捷键随版本变化,按安装版本界面设置断点、单步和监视。暂停执行可能干扰实时行为,因此断点用于状态检查,时序结论应来自另一次不暂停的 Trace。

排除三个容易误导的解释

十进制与十六进制只是同一数值的不同显示

十进制 3200 是十六进制 0xC80;0x7D0 是十进制 2000。切换显示进制不会改变存储值,更不会让假比较变真。修改阈值前先核对类型、数值和缩放。

局部变量不会因为处理器返回就自动清零

CAPL 局部变量的存储会跨调用保留。需要每次重新累加时,应每次赋零;需要持久状态时,应明确初始化与重置条件。把所有局部变量挪到 variables 并不能解决对生命周期的误解。基础练习对比了声明初始化和显式赋值。

定时器类型决定延时单位

对于 timer t,setTimer(t, 100) 是 100 秒;对于 msTimer t,才是 100 毫秒。先查声明。不要依赖臆造的 t.active、t.time 成员,应使用安装版文档支持的 API,或记录事件入口时间戳和显式诊断计数。timeNow() 单位为 10 微秒,不是纳秒。

一次定位一个层次

现象 接下来检查 为什么先查这里
编译失败 第一条编译错误、具体行和安装版 API 签名 后续错误可能由第一处引起
没有按键日志 测量是否运行、节点是否启用、键盘焦点 总线设置修不好未运行的处理器
有请求日志但没有预期 Trace 行 CAN 映射、节点位置、帧过滤和其他发送源 output 不是确认应答
有 Trace 行但接收状态错误 接收方向、DLC、解码、原始/物理值缩放 到达不代表载荷正确
第一次正常,重复后异常 初始化、持久变量、待触发定时器和缓存值 上次运行的状态可能误导本次判断

每次只改变一个实验条件。修改源码前保留失败输入序列与对应 Trace。修复后既重复正例,也重复本来就应为阴性的用例;无条件告警可能让“收到报文”通过,却破坏真正要求。

留下足够的复现信息

记录源码版本、CANoe 版本、配置、通道映射、启用的发送者、输入序列、预期分支、实际日志/Trace 证据和未解释差异。实际结果在执行前留空。只有绿色报告截图而没有输入条件,无法说明究竟测了什么。

生命周期与时间单位依据授权 Vector 参考;双来源实验和诊断决策表为本站分析。下一篇:仿真节点模型。