利用CANoe CAPL程序测试随机数重复率问题

 文章目录



前言

背景:由于UDS服务$27安全服务中需要ECU生成随机数作为种子,且ECU使用的MCU(RH850)没有随机数生成器,因此需要通过算法实现随机数。
真正意义的随机数生成器存在吗? - 知乎https://www.zhihu.com/question/20145173要求:生成的随机数种子1000次不能重复,种子长度为3 Bytes。
实现:通过随机算法实现种子生成,并通过CAPL程序检查种子重复率问题。

注:本文重在CAPL测试程序,而非随机数算法!



一、随机数生成算法

由于C标准库中的rand函数每次得到的序列都是相同的,如果想得到不同序列需要调用srand设置不同的种子,做法如下:

  • 获取随机数之前,使用单片机RTC/当前电压AD值/或全局GlobalTime(从整车CAN网络接收的时间)等作为srand 的种子以初始化随机数序列;
  • 确认rand随机数范围(所使用stdlib.h库中RAND_MAX为0x7FFF,无符号数);

示例代码(以RTC作为srand种子):

FUNC(Std_ReturnType, DCM_APPL_CODE) SecurityAccess_Level1_GetSeed(
    Dcm_OpStatusType OpStatus,
    P2VAR(uint8, AUTOMATIC, DCM_VAR) Seed,
    P2VAR(Dcm_NegativeResponseCodeType, AUTOMATIC, DCM_VAR) ErrorCode
    )
{
    static boolean isFirstRequest = TRUE;
    uint32 random = 0U;
    (void)OpStatus;

    /* Initialize random number generator with seed(RTC).*/
    if (isFirstRequest) {
        const uint32 currSysTime = SystemTime_Read_ticks_32bits();
        srand(currSysTime);
        isFirstRequest = FALSE;
    } else {
        ;
    }

    /* Generate the random number. the RAND_MAX is 0x7FFF in _gh stdlib.*/
    random  = (uint32)(rand());
    random += (uint32)(rand()<< 15U);

    Seed[0] = (uint8)(random);
    Seed[1] = (uint8)(random >> 8U);
    Seed[2] = (uint8)(random >> 16U);

    *ErrorCode = DCM_E_POSITIVERESPONSE;
    return E_OK;
}


二、CAPL程序测试


1.关联类型&用法

为了实现快速查找比对重复的随机数,需要使用到类似C++中的map容器进行查找,而map集合特点:

  • 采用了 Key-value键值对映射的方式进行存储,且存储是无序的(散列的);
  • Key在Map里面是唯一的但是value可以重复,一个Key对应一个Value;

而CAPL有一种特殊的关联类型(Associative Fields),类似Python字典和C++ Map容器,其关联类型的元素也是键值对(key value pairs)。
从CANoe帮助文档中查看用法,如下:

 关联类型定义格式如下对象左边是Value类型,右边[ ]内是Key类型

int      m[ float  ];  // maps floats to ints
float    x[ int64  ];  // maps int64s to floats
char[30] s[ char[] ];  // maps strings (of unspecified length) to strings of length < 30

官方示例1:关联浮点型 

float m[float];    // 定义关联对象
m[4.1] = 5.5;      // key is 4.1 (float)  and value is 5.5 (float)
m[5.3] = 6.6;
write ("4.1 is mapped to %2.2lf", m[4.1]);
write ("5.3 is mapped to %2.2lf", m[5.3]);
for (float mykey : m)
{
  write("%2.2lf is mapped to %2.2lf.", mykey, m[mykey]);
}

 官方示例2: 关联字符串

char[30] namen[char []];                    // 定义关联对象
strncpy(namen["Max"], "Mustermann", 30);    // 相当于 namen["Max"] = "Mustermann"
strncpy(namen["Vector"], "Informatik", 30); // 相当于 namen["Vector"] = "Informatik"

for (char[] mykey : namen)
{
  write("%s is mapped to %s", mykey, namen[mykey]);
}

关联对象方法(Associative Fields CAPL Functions): 

本测试代码则用到map中的key唯一的特性,将随机数作为key,对应的value可以是任意类型数据(由于不关心,统一设置为整型数据1),然后通过::containsKey()方法进行查找。
如果::containsKey(randomNum)返回1,则表示该key(随机数randomNum)已经存在,否则将其插入到关联类型中。


2.测试程序

假设:

  • 诊断物理请求ID & 响应ID分别为:0x705 & 0x745
  • 通过安全访问服务$27 01 请求获得种子(随机数,3个字节)

代码如下(示例):

on message 0x745       /* VCU_DiagResponse.*/
{
  int  seedMap[long];  /* Maps long to int */
  byte isDuplicateOccur = 0;
  long randomNum = 0;
  long index = 0;
  
  if ( (!isDuplicateOccur)
    && (this.byte(1) == 0x67) && (this.byte(2) == 0x01))
  {
    randomNum =  this.byte(3);
    randomNum <<= 8;
    randomNum += this.byte(4);
    randomNum <<= 8;
    randomNum += this.byte(5);
    
    /* Check if this random number is duplicated,
     * if not - insert this random number as key and the value is 1.*/
    if (seedMap.containskey(randomNum)) {
      write("Seed %6d: %06X =======> Duplicated seed is FOUND!!!", index++, randomNum);
      isDuplicateOccur = 1;
    } else {
      seedMap[randomNum] = 1;
      write("Seed %6d: %06X", index++, randomNum);
    }
    
#if (0) /* CAPL map test code.*/
    switch (index)
    {
    case 1: 
      seedMap[0x123456] = 1;
      write("Seed %6d: %06X", index++, 0x123456);
      break;
    case 1000:
      if (seedMap.containskey(0x123456)) {
        write("Seed %6d: %06X =======>  Duplicated seed is FOUND!!!", index++, 0x123456);
        isDuplicateOccur = 1;
      }
      break;
    default:
      break;
    }
#endif
  }
}


参考

rand - C++ Reference
map - C++ Reference

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQL SERVER 的函数<br>1.字符串函数 <br>长度与分析用 <br>datalength(Char_expr) 返回字符串包含字符数,但不包含后面的空格 <br>substring(expression,start,length) 不多说了,取子串 <br>right(char_expr,int_expr) 返回字符串右边int_expr个字符 <br>字符操作类 <br>upper(char_expr) 转为大写 <br>lower(char_expr) 转为小写 <br>space(int_expr) 生成int_expr个空格 <br>replicate(char_expr,int_expr)复制字符串int_expr次 <br>reverse(char_expr) 反转字符串 <br>stuff(char_expr1,start,length,char_expr2) 将字符串char_expr1中的从 start开始的length个字符用char_expr2代替 <br>ltrim(char_expr) rtrim(char_expr) 取掉空格 <br>ascii(char) char(ascii) 两函数对应,取ascii码,根据ascii吗取字符 <br>字符串查找 <br>charindex(char_expr,expression) 返回char_expr的起始位置 <br>patindex("%pattern%",expression) 返回指定模式的起始位置,否则为0 <br>2.数学函数 <br>abs(numeric_expr) 求绝对值 <br>ceiling(numeric_expr) 取大于等于指定值的最小整数 <br>exp(float_expr) 取指数 floor(numeric_expr) 小于等于指定值得最大整数 <br>pi() 3.1415926......... <br>power(numeric_expr,power) 返回power次方 <br>rand([int_expr]) 随机数产生器 <br>round(numeric_expr,int_expr) 安int_expr规定的精度四舍五入 <br>sign(int_expr) 根据正数,0,负数,,返回+1,0,-1 <br>sqrt(float_expr) 平方根 <br>3.日期函数 <br>getdate() 返回日期 <br>datename(datepart,date_expr) 返回名称如 June <br>datepart(datepart,date_expr) 取日期一部份 <br>datediff(datepart,date_expr1.dateexpr2) 日期差 <br>dateadd(datepart,number,date_expr) 返回日期加上 number <br>上述函数中datepart的 写法 取值和意义 <br>yy 1753-9999 年份 <br>qq 1-4 刻 <br>mm 1-12 月 <br>dy 1-366 日 <br>dd 1-31 日 <br>wk 1-54 周 <br>dw 1-7 周几 <br>hh 0-23 小时 <br>mi 0-59 分钟 <br>ss 0-59 秒 <br>ms 0-999 毫秒 <br>日期转换 convert() <br>4.系统函数 <br>suser_name() 用户登录名 <br>user_name() 用户在数据库中的名字 user 用户在数据库中的名字 <br>show_role() 对当前用户起作用的规则 <br>db_name() 数据库名 <br>object_name(obj_id) 数据库对象名 <br>col_name(obj_id,col_id) 列名 <br>col_length(objname,colname) 列长度 <br>valid_name(char_expr) 是否是有效标识符
### 回答1: Canoe CAPL编程实例包括很多方面,例如网络通讯、数据传输、故障诊断和测试等。其中有一些比较典型的例子如下: 1、网络通讯实例: 在Canoe CAPL编程中,可以使用CAPL库函数对网络进行通讯。通过发送CAN消息可以在网络中进行数据的传输。例如,在测试中,我们可以模拟发送一条CAN消息,并且在接收到回传消息后进行判断,可以通过判断结果来进行测试。 2、数据传输实例: Canoe CAPL编程可以方便地进行数据的传输。例如,可以对多个CAN信号进行检测和处理,可以通过处理之后得到特定的数据内容。此外,还可以进行多种格式的数据处理,例如对BCD码、二进制码、十六进制码等进行解析。 3、故障诊断实例: Canoe CAPL编程可以实现对网络故障的诊断,通过在网络中发送和接收命令,可以进行网络的测试和检测,确保网络的健康。例如,在接收数据时,如果出现错误信息,则可以判断出网络出现了故障。 4、测试实例: Canoe CAPL编程也可以进行测试。例如,在汽车制造中,可以验证CAN网络的正确性,对CAN总线上的数据进行检查,以确保汽车的安全性。另外,还可以模拟传感器、控制单元等,以检测其他部件的正确性。 总之,Canoe CAPL编程实例是非常广泛的,包括了很多方面的内容,通过对这些实例进行学习和应用,可以达到更好地进行数据处理、网络通讯、故障诊断和测试的目的。 ### 回答2: Canoe CAPL编程是面向嵌入式系统的一种高级编程语言,能够帮助开发者进行控制单元的软件开发、测试和调试等工作。下面就介绍一下Canoe CAPL编程的实例。 我们可以通过Canoe CAPL编程来控制汽车中的某些功能模块,例如车门、车窗、车灯、音响等。可以编写一系列的函数,通过向不同的功能模块发送信号,来控制它们的状态。比如,我们可以定义一个函数,来控制车门的状态。通过编写如下代码: on key 'F4' { setDoorState(1); //打开车门 } on key 'F5' { setDoorState(0); //关闭车门 } void setDoorState(int state) { if(state == 1) { setSignal(DOOR_SIGNAL, 1); //发送打开车门的信号 } else { setSignal(DOOR_SIGNAL, 0); //发送关闭车门的信号 } } 在这个代码中,我们首先定义了两个按键,用来控制车门的状态。当用户按下F4键时,调用setDoorState函数,将车门打开;当用户按下F5键时,调用setDoorState函数,将车门关闭。setDoorState函数根据传入的状态参数,向DOOR_SIGNAL信号发送对应的数值(1为打开车门,0为关闭车门),从而实现控制车门状态的功能。 另外,Canoe CAPL编程还可以用于信号的模拟和调试。在开发过程中,我们可以通过编写一些模拟代码,来模拟接收到不同数据信号的情况,并进行相关的处理。这样就可以将信号的处理过程模拟出来,提前发现并解决潜在的问题。 总之,Canoe CAPL编程可以帮助汽车系统开发者快速地开发出控制单元的软件,并进行测试和调试,是一种非常实用的编程语言。 ### 回答3: Canoe CAPL编程实例是指用Vector公司的CANoe工具编写以CAPL语言为基础的程序来控制CANape的功能。 CANoe是一款用于开发、测试和分析基于CAN总线的系统的软件工具,支持多种总线,如CAN、LIN和FlexRay等。CAPLCANoe中一种专门用于CAN总线开发的高级编程语言,广泛应用于CAN总线控制程序的编写和测试。 一个典型的Canoe CAPL编程实例是用CAPL语言编写一个简单的CAN总线消息接收程序。该程序可以接收从CAN总线上发送过来的CAN消息,并将其显示在CANoe的消息窗口中。 这个程序实现步骤如下: 1.定义变量:定义一个变量来保存接收到的CAN总线消息。 2.定义事件:通过事件触发来处理CAN总线消息。 3.创建回调函数:定义一个回调函数,用来处理CAN总线上接收到的消息,并将其保存到变量中。 4.初始化事件:初始化事件,以便接收CAN总线上的信息,然后在事件处理程序中调用回调函数。 5.启动测试:启动CANoe测试后,该程序就可以在CAN总线上接收消息并将其显示在CANoe的消息窗口中了。 总之,Canoe CAPL编程实例是一个重要的工具,可以帮助工程师们更好地开发、测试和分析CAN总线系统,从而提高生产效和质量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值