HIL测试中的CheckSum和RollingCounter
CheckSum和RollingCounter是为谁而生的?答,通信安全!虽然CAN自带CRC,但这个额外的CheckSum绝不是画蛇添足~RollingCounter,也有人称呼它为LiveCounter,它也绝对不是想有些人字面上想的那样,看到数字在变动,说明总线还“活着”,没有休眠!它不是用来区分总线是不是还“活着”的!博世的锅
博世在发明CAN总线技术的时候,是自带CRC校验功能的。但是这个东东不在数据区,而且它只确保对方也是CAN节点,在传输的过程中没有发生突变,仅此而已。至于对方是不是合法的,还是一个冒牌的CAN节点,博世发明的这个CAN协议自带的CRC无法识别。【恶果】这就导致了问题:公司内部的工程师,知道CAN定义的,可以直接用CAN卡往车上发报文。且不说他目的是好是坏,这样做,毫无疑问具有很大的安全隐患,轻者逻辑混乱,重则安全事故。社会人员,稍微懂点汽车电子的人,截获了一段报文,稍加分析,总结出规律,也可以往车上发报文,危险性就更大了。CheckSum对策
怎么办呢?首先,要增加CAN校验功能,让接收方意识到,是车上的合法控制器发的,还是外部黑客发进来的。自定义CheckSum就应运而生了!有别于CAN链路层自带的CRC,这个自定义CheckSum位于数据区,它可以对数据区的其他字节计算,生成一个值,放在报文里。接收方用相同的方式解析,看是不是一样,从而确认出发送方的身份。不知道这个CheckSum算法的人,一般很难冒充车上的节点。可是,这就解决问题、一劳永逸了吗?显然不是。CheckSum算法,对公司内部人员,还是能得到的,而且,随着行业技术的相互交流,CheckSum已经开始部分雷同了,很容易得到了。怎么办呢?RollingCounter对策
然后,RollingCounter就诞生了。这个东东的作用就是,某个ID,每发一次,自加1,循环计数。这个东西的意义师子一号就不再赘言了,反正,你不把线束拆开的话,已经很难再侵入汽车通信网络了。一般而言,商用车由于技术标准相对低一些,面向商用、安全性要求没有民用那么高,是没有这两个东东的;乘用车,一般是必须有的。通信协议,是整车设计最后的脸面,如果一个公司,连总线都是找外包公司做的,那这家企业基本可以说没有任何自主设计能力可言了。今天师子一号讲讲,CheckSum和RollingCounter在Veristand中如何做,它们都是非常重要的“第一类闭环模型”!Simulink实现
Matlab可以做,有些库可以完成这样的工作,用matlab的simulink,给VCU做图形化代码开发的时候,也只能这么做,一般都是供应商提供库,直接用就好了,下图中的S-function就可以实现自定义CheckSum的功能。我们后续会详细介绍如何做。
在HIL台架上,可以通过“模型”来做,编译成DLL,可以对即将发出去的报文进行计算,添加上CheckSum和RollingCounter。但是这种做法需要自己干活的地方比较多,重复劳动量比较大,师子一号不太推荐。固件库实现
师子一号推荐在Veristand中做,因为它在部署的时候,会直接烧写到CAN卡里,这样在报文即将发送的时候,才会添加上CheckSum和RollingCounter,这样最地道、最正宗,也最可靠,处理速度最快,不受其他限制因素影响。在Veristand中自带的有CheckSum和RollingCounter,默认情况下VeriStand的XNET AFP(Automatic Frame Processing)提供了CRC8和CRC16这两种Checksum算法,如果满足您的需求,直接勾选配置就可以了。但是,作为一家有追求的汽车企业,通用型的Checksum显然不应该是您的长期之计,这明显不利于通信安全,大家都一样了,破解就很简单了,这对客户是不负责任的。创建企业自主、自定义的算法,使用专门的Checksum,才是您的最终目的。下面我们就来讲讲,HIL里面如何做自定义的CheckSum(rollingcounter就不存在自定义的概念了),从而与您的VCU的自定义Checksum,配合起来。VeriStand中AFP addon可以通过给CAN口烧写firmware的方式对Frame的Checksum和LiveCounter信号进行自定义处理。这个firmware方法是XNET驱动对于CAN口预留的功能,本文主要介绍如何编写这个firmware,并且如何利用VeriStand中现有的XNET AFP接口来进行Checksum和LiveCounter的自定义源码详解
1.首先需要确定Checksum算法,将自定义的算法编写成C文件,在这个C文件中会处理CAN的frame信息。下面是这个C文件的算法函数原型:
原型中定义了a_Mode的三种模式:
可以从a_Mode定义的模式可以看出, transmitPreprocess函数会在3种情况下被调用:a.其中两次被调用是在设置XNET Session-Intf.CustCode.Data这个属性节点的时候。
这个属性节点会首先调用a_Mode=kUserCodeMode_RequestMemorySize模式下的函数,在这个模式下函数主要为接口数据设置内存大小(return的值就是这块内存的大小),在这片内存里可以放置全局变量。具体内存的大小可以根据算法的实现和属性节点的Intf.CustCode.Data输入端接入的数据来决定,比如Checksum是通过查表法来实现的,那么在申请的这块内存里就可以放置查询的那个对照表,那么这里返回的就是这个查找表的大小(单位byte),当然如果你的Checksum算法不需要内存空间,这里返回的值也可以是0。但要注意的是这里返回的值必须是4的倍数,即必须要与32bit对齐,我个人猜测XNET CAN板卡中的内存是32位宽的,因此需要32bit对齐。第二次被调用是在第一次调用后自动运行的,这次的模式是kUserCodeMode_InitMemory,即初始化内存模式。这次属性节点的Intf.CustCode.Data输入端数据会被再次传入到函数中,即函数中的a_pContextData这个参数。同样地,假设用的是查表法,在这个模式下就可以初始化*a_pMemory这块内存了。第三次被调用是在调用XNET Session属性节点-Frm.CustCode.Data的时候。
这时的模式是kUserCodeMode_PreTransmitData模式,并且连接到Frm.CustCode.Data端口的32bit数组数据会以a_pContextData参数传入transmitPreprocess函数中,之前初始化过的*a_pMemory也会传递给这次调用的函数中。函数中的参数a_pDataFrame对应的是即将发送的CAN frame数据,在这个模式下可以对frame元数据进行处理,实现自定义Checksum算法和LiveCounter,并且把计算出的结果替换到a_pDataFrame中。最后CAN卡将处理过的a_pDataframe数据发送出去,因此我们主要在这个模式下编写具体算法部分。 注:附件中给了一些.c范例,大家可以参考范例进行编写。但是VeriStand中的AFP功能有固定的a_pContextData格式,主要参考CRC8算法的格式,后面我会具体说明。 2.准备好.c文件后,下面我们就可以对它进行编译了。在编译前首先修改附件里带的Makefile文件,在Makefile文件的第7行,添加你自定义的.C文件名称: C_SRCS += YOUR_FILE.c 保存修改,并将Makefile文件放置到与.C文件同一个文件目录下。这里用到的编译器是Altera Quartus II自带的NIOS II编译器。大家可以到网上自行下载Quartus II,我用的是Quartus II 11.0,我们所需要的功能无需激活Quartus II。在安装完Quartus II后,到开始菜单-所有程序-Altera-NIOS II EDS 11.0 找到NIOS II 11.0 Command Shell,双击打开,输入:cd /cygdrive/X/”Your directory”注意:X是.C文件路径的盘符,在盘符前,必须加上/cygdrive,Your directory是你的.C 和Makefile文件路径。 在你索引到你的路径之后,输入”make”来编译你的.C文件,最终shell命令会将.C文件编译成.enb文件,存放在路径下新建的obj文件夹中,如下图所示:
在编译成enb文件后,你可以通过附件中CAN.lvproj中的Checksum_Verification.vi来验证enb算法的正确性。
3.在VeriStand XNET中添加AFP功能。 在VeriStand的System Definition File中可以对XNET进行配置AFP功能,具体步骤如下: 1) 首先先添加一个CAN口,定义好CAN port和database。 2) 在右侧的配置选项卡中可以看到有一个Automatic Frame Processing,点击选中这个选项卡,进入AFP配置界面。 3) 在下拉框中就可以看到VeriStand中目前有的AFP方法函数,默认状态下只有None(即不进行AFP),CRC8和CRC16。这里如果选择CRC8后,在这个页面中还会有一些参数可以配置,这些参数是上述transmitPreprocess函数的第二种mode(kUserCodeMode_InitMemory,)下需要用到的参数,即是在初始化内存时的输入参数a_pContextData 。 4) 在选择了enb方式之后,可以在cyclic或者是event下添加frame,在添加frame后会将frame的所有signal导入。 5) 右击添加的frame,在快捷菜单栏里可以看到有Add Automatic Frame Processing Data这个选项,点击添加这个AFP data。 6) 添加完后,会在该frame下看到AFP data,一共有两项,分别是CRC和Counter。 7) 选中CRC后,右边就会出现CRC的配置界面。其中First included byte,Last included byte和storage offset byte分别代表进行Checksum的起始位、结束位和保存位,Use alternate channel 如果不打勾的话,默认就会进行Checksum,如果打勾了,可以另外配置触发Checksum的通道,如果该通道的值为0,则不进行Checksum计算,如果非零,则进行Checksum。 8) 选中Counter后,右边就会出现Counter的配置界面,包括位宽,初始值,存放的位置(Byte offset和Bit Offset)和触发通道,同样如果通道的值为0,则Counter位不计数。
VeriStand XNET底层会调用Frm.Custcode.Data属性节点来将CRC和Counter的配置参数传入固件中。
注意:(非常重要) a_pContextData定义: SDF中XNET工具也是一个Custom Device(CD),不过是VeriStand集成好了的CD,所以我们在编写.C算法时需要注意Frm.Custcode.Data的数组定义,即.C文件中定义的函数参数a_pContextData。对于自带的CRC8和CRC16这两种方法,XNET框架中是通过以下这种顺序将数据传入到a_pContextData,这个数组一共八个元素:
所以在.C代码中才会有以下注释:// CRC Storage// a_pContextData[0] = WidthInBits, // Width of the counter, in bits// a_pContextData[1] = Location, // Location of counter in frame// // Lower 16-bits is the byte// // Upper 16-bits is the bit offset// a_pContextData[2] = Storage, // Location to store the counter// a_pContextData[3] = Enabled // Whether to use the counter// CRC Storage// a_pContextData[4] = StartLocation, // First byte to include in CRC// a_pContextData[5] = EndLocation, // Last byte to include in CRC// a_pContextData[6] = Location, // Location to store the CRC// a_pContextData[7] = Enabled // Whether to use the CRC所以如果需要自定义Checksum和LiveCounter,需要用到自带的这些接口定义。当然也可以不用这些接口定义,但是那样的话需要修改XNET CD源码并且重新编译XNET.llb,因为XNET CD这段源码是不开放的,所以不建议这么做,并且原来留有的接口完全可以满足大部分的要求。4.在了解了AFP设置和a_pContextData定义后,我们就可以自由定义checksum 和LiveCounter了。在编译完.C文件得到.enb文件后,还需要做如下操作: 1) 将之前编译得到的.enb文件放到C:\ProgramData\National Instruments\NI VeriStand 2013\System Explorer\XNET\AFP\National Instruments文件夹中,根据电脑安装的VeriStand版本修改以上路径。2) 在C:\ProgramData\National Instruments\NI VeriStand 2013\System Explorer\XNET\AFP文件下新建一个ini文件,可以复制自带的NI VeriStand 2011_CRC8.ini,假设enb文件名为fwTxPreprocess_XorCFI3v.enb,则将复制之后的ini文件命名为fwTxPreprocess_XorCFI3v.ini。通过系统自带的notepad打开这个ini文件,就可以看到如下代码:[AFP]BinaryFile = 'National Instruments/ NI VeriStand 2011_CRC8.enb'GlobalSettings = 'National Instruments/NIAFP.llb/Global Settings_CRC8.vi'CRC = 'National Instruments/NIAFP.llb/CRCConfig.vi'CTR = 'National Instruments/NIAFP.llb/CTRConfig.vi'将fwTxPreprocess_XorCFI3v.enb替换代码中的NI VeriStand 2011_CRC8.enb,其中Global Settings_CRC8.vi是transmitPreprocessing函数kUserCodeMode_InitMemory模式下的a_pContextData配置页面,这个vi的前面板就是选择完AFP方法后出现的配置界面,如下图所示。
而CRCConfig.vi和CTRConfig.vi这两个vi就是我们之前在VeriStand中配置CRC和Counter时出现的界面。因为我们利用的是自带的Checksum和LiveCounter的接口,所以这三行不需要修改。保存ini文件,重启VeriStand后就可以在Automatic Frame Processing界面中看到新添加的fwTxPreprocess_XorCFI3v方法。CheckSum和RollingCounter弄好了之后,我们的HIL才算是可以正儿八经地用起来了,才真的算有点逼格了,尤其是在乘用车测试领域,没有CheckSum和RollingCounter,出门不好意思跟同行打招呼的。