Vspy工程之C Code Interface的使用(Vspy系列其三)
1、通过C Code Interface新建vs工程
通过Vspy提供的C Code Interface接口,我们可以在其生成的C工程代码上进行二次编程开发,以完成更为复杂的功能需求。在已经建好的vspy工程中添加C Code Interface的vs工程的步骤如下,注意电脑需要安装上VS/VC软件。
(1)、点击工具栏”Scripting and Automation”下的”C Code Interface”,此时界面如下:
(2)、点击上图的”Add Project”,此时可以选择新建工程或者导入已有工程;我们这里以新建工程为例:点击”New Project”,输入要创建的工程名字和描述,点击ok,此时就已经完成vs工程的创建了(注意新建的vs工程,需要先打开vspy工程进行编译生成dll文件;此时才能正常调用c code interface功能)。此时界面如下:
Ps:上图中的"Output"界面用于输出我们在工程中调用"Printf()"函数输出的字符内容;可以用于调试,方便我们定位问题。
2、C Code Interface的使用
当我们按照前面步骤通过Vspy的C Code Interface创建好vs工程时,已经将该Vspy工程的所有数据信息(比如该vspy工程中的报文、定义的App Signal、Function Block等信息)写入到vs工程文件中了(在vspy.c和vspy.h这两个文件中体现);同时自动生成了工程的主函数的 Spy_Main()。
2.1、点击”C Code Inteface”界面下的”Edit”(或者双击下面的工程名),进入编辑界面
2.2、如下,可以在对应的报文类型(Rx/Tx/Db)中选择指定的报文作为报文事件、选择工程中已经定义好的App Signal作为应用信号事件、添加时间事件;
(1)、双击左侧想要添加为事件的报文或应用信号(此时右侧边框会更新显示);
(2)、点击”Event Handle Code”,就可以看到我们新增进来的事件代码函数接口;如下:
(3)、将自动生成的事件函数接口代码拷贝到SpyCCode.c中,在该接口函数里添加自己要处理的c代码;当对应的事件发生时,则会调用该函数(如对应的App Signal值有输入时触发的App Siganl事件;定时时间到达触发的定时器事件等)。
Ps:当我们对Vspy工程进行改动后,例如对报文、应用信号、事件等的新增或修改;需点击上图的”Update Support Files”,将Vspy上的改动信息同步更新到vs工程文件中去。再通过其生成的接口函数对其进行操作。
3、自动生成的函数接口解析
当我们通过Vspy的C Code Interface完成对应vs工程的生成时,该Vspy工程的所有数据信息(比如该vspy工程中的报文、定义的App Signal、Function Block等信息)也已经在vspy.c、vspy.h这两个文件中生成了。接下来,我们就针对vspy工程中自动生成的函数接口进行介绍;以便大家对函数接口的理解及调用。
3.1、针对vspy工程中的Function Block生成的函数接口
函数及变量以”FB_”开头,在Vspy 工程中定义了” OpenTurnRightAlarm”这个Function Block ;以此为例,通过C Code Interface自动生成的vs工程中包含该Block的操作函数如下,可以直接在程序中调用这些接口函数对Function Block进行操作;如**开始(_Start)/暂停(_Stop)**等操作。
3.2、针对vspy工程中定义的App Signal生成的函数接口
函数及变量以”AS_”开头,如下,我们在Vspy工程中创建了两个应用信号,一个是名为”Num1”的数值类型应用信号;另一个是名为”Path”的文本型应用信号。通过C Code Interface自动生成的vs工程中包含该应用信号的操作函数有:
其中,对于数值型的应用信号主要就是_Get、_Set操作接口,用于对数值型应用信号值的获取和设置;对于文本型的应用信号主要是_GetText、_SetText操作接口,用于对文本型应用信号值的获取和设置,常用于文件打开操作时文件路径的传递。
3.3、针对vspy工程中定义的时间事件生成的函数接口
函数以”Tmr_”开头,如下,我们在Vspy工程中创建了一个名为"TimerEvent1"的时间事件;
在”Event Handler Code”将生成的事件函数接口考到c代码中,在里面添加想要执行的周期代码;则在vspy工程启动时会周期性(上例中每500ms执行一次)地执行该事件的代码块。
对于我们创建的这个名为”TimerEvent1”的时间事件,通过C Code Interface自动生成的操作函数如下,可以通过生成的接口函数对该时间事件进行使能(_Enable_Set)、周期设置(_SetPeriod)等操作。
3.4、生成的通用函数接口
如下,这些函数在通过Vspy的C Code Interface创建vs工程时在SpyCode.c中自动生成的(如主函数Spy_Main也是其中之一);可以根据需要使用这些接口函数进行功能开发。例如通过"Spy_EveryMessage"函数在接收到指定报文后进行解析或提示操作;通过"Spy_ErrorFrame"函数在检测到错误帧进行错误处理或提示等。
3.5、其他不常用的函数接口
(1)、SpyShowPanel()函数:用于在C代码中实现调出Panel面板;如:
SpyShowPanel(“Graphical Panels”, “Panel 1”); /调出“Graphical Panels”栏下的”Panel 1”面板/
(2)、在C代码中调用vspy工程中的诊断报文;例如我们定义了一个名为” 10 Diagnostic Session Control Job”的诊断报文;则其生成的接口函数是以DG_开头的,如下,可以根据需要调用函数接口在C代码中进行诊断工作,如开始(_Start)/停止(_Stop)操作等。
Ps:关于Vspy工程中诊断报文的定义,可以直接导入cdd诊断数据库文件(步骤可参考"vspy常用操作"一文中关于导入cdd的操作);也可以在工具栏”Spy Networks”下的”Setup Diagnostics”中进行添加;如下:
3.6、针对vspy工程中的报文生成的函数接口
(1)、接收报文:函数及变量以”MG_”开头,在Vspy工程中定义了”TPMS”这个接收报文,以此为例,通过C Code Interface自动生成的vs工程中包含该报文的操作函数如下(注意函数名中的HS_CAN 代表该报文所属的CAN网络,不是一定的值):
(2)、发送报文:函数及变量以”TX_”开头,在Vspy工程中定义了”BCM”这个发送报文;以此为例,通过C Code Interface自动生成的vs工程中包含该报文的操作函数如下:
(3)、DBC中的报文:函数及变量以”DB_”开头,在Vspy工程中添加了dbc,dbc文件中包含了”ACC1”这个报文;以此为例,通过C Code Interface自动生成的vs工程中包含该报文的操作函数如下:
4、报文发送的函数接口
4.1、_TransmitFast()函数
如3.6小节中对发送报文生成的函数接口中,有一个比较特殊的函数接口_TransmitFast();该函数接口是只有定义为发送报文才会生成的;通过调用接口可以将报文完全按照我们在vspy中定义的格式内容进行发送,不需像_Transmit()函数那样得自己定义报文格式内容。
4.2、_Tranmit(参数)函数
需先用生成的类型定义一个报文变量;然后手动设置该报文变量的发送信息;再通过该函数进行发送(也可以不设置信号值,直接定义报文变量进行发送,此时的功能则和_TransmitFast 一致);如下:
void Spy_Main()
{
do
{
Sleep(100);
TX_EMS3_HS_CAN stMsg;/*创建TX_EMS3_HS_CAN类型变量,该类型是根据vspy中定义的“EMS3”这一报文自动创建的*/
TX_EMS3_HS_CAN_Init(&stMsg);/*该函数是根据vspy中的“EMS3”这一报文自动创建的,用于初始化*/
stMsg.MessageData.btData[0] = 0x0; /*设置报文信息内容*/
stMsg.MessageData.btData[1] = 0x1;
stMsg.MessageData.btData[2] = 0x2;
stMsg.MessageData.btData[3] = 0x3;
stMsg.MessageData.btData[4] = 0x4;
stMsg.MessageData.btData[5] = 0x5;
stMsg.MessageData.btData[6] = 0x6;
stMsg.MessageData.btData[7] = 0x7;
stMsg.MessageData.iNumDataBytes = 8; /*设置报文长度*/
TX_EMS3_HS_CAN_Transmit(&stMsg); /*发送报文*/
} while (1);
}
如上,在主函数中通过生成的"TX_EMS3_HS_CAN"类型创建了报文变量,对其进行发送内容和长度的手动设置后,通过生成的_Transmit函数进行发送。编译更新dll文件,打开vspy工程,在”Message”界面下可以看到该报文已经按照我们定义的发送出来了。
4.3、GenericMessageTransmit(参数)函数
需自己定义报文的结构信息,再调用该函数进行定义的报文发送操作。当需要发送vspy工程中未定义的报文时,即可以通过通用的报文属性("GenericMessage"类型)定义报文变量,设置好要发送的报文ID、内容、长度等信息,并通过该函数来进行发送操作。如下:
void Spy_Main()
{
do
{
Sleep(100);
GenericMessage stMsg = { 0 }; /*定义GenericMessage类型的报文变量*/
stMsg.iNetwork = NET_HS_CAN; /*定义该报文网络*/
stMsg.iID = 0x555; /*定义该报文ID*/
stMsg.iNumDataBytes = 3; /*定义该报文长度*/
stMsg.btData[0] = 0x55; /*定义该报文信息内容,未进行值设置的自动补充0*/
stMsg.btData[1] = 0x5;
GenericMessageTransmit(&stMsg);
} while (1);
}
如上,在主函数中我们定义了一条0x555的报文,对其内容和长度进行手动配置,并通过GenericMessageTransmit()函数进行发送。编译更新dll文件,打开vspy工程,在”Message”界面下可以看到该报文已经按照我们定义的发送出来了。
Ps:GenericMessage 是vspy中对于报文定义的结构体类型(在vspy中定义的报文也是这个类型);当我们需要在vs工程中自定义报文进行发送时,需要定义一个该类型的报文变量,如上例中的stMsg变量。其结构如下:
4.4、对上述三种发送函数的总结
(1)、当我们在vspy中定义好了要发送的报文信息(注意是作为发送报文),并且不需改动到报文内容时,可以直接使用该报文生成的_TransmitFast()函数接口进行发送操作(直接调用,方便快捷);
(2)、当我们在vspy中定义好了报文信息,但在发送过程中需要对其信号内容进行改动或赋值时,则可以通过调用该报文生成的类型创建一个报文变量,对其进行发送内容和长度的手动设置后,通过生成的_Transmit函数进行发送操作;
(3)、当我们要发送的报文是原先vspy工程中没有定义过的,是我们直接自定义的,即并没有通过C Code Interface生成对应的函数接口时。可以自己通过通用的报文信号"GenericMessage"类型创建一个报文变量,对其进行发送内容和长度的手动设置后,通过GenericMessageTransmit()函数进行发送操作。