1. USBCAN分析仪国内现状

这是目前国内市场上的USBCAN分析仪现状。

2. 创芯科技产品

创芯科技的这个红色盒子是我比较下来综合性价比最高的。同时支持windows和linux的设备只要320元左右。你既可以用可视化界面发送/接收报文,也可以二次开发,设置复杂的收发以及数据处理的逻辑。可视化界面操作很简单,我就不赘述了,主要谈谈怎么基于linux二次开发。

2.1 设备自测

设备拿到时最好进行自测,判断设备是否可用。

自测时设备线路连接如下:

PC上virtualbox安装ubuntu虚拟机的USB接口选择

执行自测用例

root@zyy-VirtualBox:/home/zyy/controlcan# ls
controlcan.h  hello_cpp  libcontrolcan.so  main_bak.cpp  main.cpp  Makefile
root@zyy-VirtualBox:/home/zyy/controlcan# rm -r hello_cpp
root@zyy-VirtualBox:/home/zyy/controlcan# make clean
rm -f *.o hello
root@zyy-VirtualBox:/home/zyy/controlcan# make
g++ -o hello_cpp main.cpp /home/zyy/controlcan/libcontrolcan.so  -lpthread
root@zyy-VirtualBox:/home/zyy/controlcan1# ./hello_cpp
>>this is hello !
>>USBCAN DEVICE NUM:1 PCS
Device:0
>>Get VCI_ReadBoardInfo success!
>>Serial_Num:31F100016D6
>>hw_Type:CAN-Linux
>>Firmware Version:V3.40
>>
>>
>>
>>open deivce success!
>>Get VCI_ReadBoardInfo success!
>>Serial_Num:31F100016D6
>>hw_Type:CAN-Linux
>>Firmware Version:V3.40
Index:0000  CAN1 TX ID:0x00000000 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07
Index:0001  CAN2 TX ID:0x00000001 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07
Index:0002  CAN2 RX ID:0x00000000 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D81E
Index:0003  CAN1 TX ID:0x00000002 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07
Index:0004  CAN1 RX ID:0x00000001 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D85C
Index:0005  CAN2 TX ID:0x00000003 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07
Index:0006  CAN2 RX ID:0x00000002 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D890
Index:0007  CAN1 TX ID:0x00000004 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07
Index:0008  CAN1 RX ID:0x00000003 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D8B6
Index:0009  CAN2 TX ID:0x00000005 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07
Index:0010  CAN2 RX ID:0x00000004 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D8E8
Index:0011  CAN1 TX ID:0x00000006 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07
Index:0012  CAN1 RX ID:0x00000005 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D912
Index:0013  CAN2 TX ID:0x00000007 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07
Index:0014  CAN2 RX ID:0x00000006 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D93D
Index:0015  CAN1 TX ID:0x00000008 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07
Index:0016  CAN1 RX ID:0x00000007 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D96F
Index:0017  CAN2 TX ID:0x00000009 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07
Index:0018  CAN2 RX ID:0x00000008 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D99F
Index:0019  CAN1 RX ID:0x00000009 Extend    Data   DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D9DC
run thread exit

2.2 基于实际场景的二次开发

2.2.1 一种测试场景

将目标ECU的CAN引脚和USBCAN分析仪相连, 目标ECU的电源引脚接到相应电压的供电电源上。

关于ECU刷写,这篇博客写得比较简洁又清晰

can例程 ecu_基于CAN的ECU刷写流程_司马各的博客-CSDN博客

我得测试场景分六步,后续步骤大同小异,可以仿照前几步格式添加。

1. 进入扩展会话模式,并获得正面响应。

2. tester向ECU请求seed,并获得seed。

3. tester根据seed计算key, tester向ECU发送key,并获得正面响应。

4. 进入编程会话,并获得正面响应

5.tester向ECU请求seed,并获得seed。

6.tester根据seed计算key, tester向ECU发送key,并获得正面响应。

针对ECU刷写的OTA升级的步骤资料可以查阅

新能源汽车OTA升级中的UDS通信分析_晓翔仔的博客-CSDN博客

2.2.2 编写代码以及调试

代码里组装的报文符合UDS协议,UDS描述见:

统一诊断服务(UDS)_晓翔仔的博客-CSDN博客

编写代码如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include "controlcan.h"#include <ctime>
#include <cstdlib>
#include "unistd.h"#define  NO_RES_COUNT_MAX  10   //等待响应的时间(周期)上限VCI_BOARD_INFO pInfo;//用来获取设备信息。
int count=0;//数据列表中,用来存储列表序号。
VCI_BOARD_INFO pInfo1 [50];
int num=0;//重要全局变量
//int i;
int STEP=0X01;  //CAN数据发送和接收的步骤,用于控制步骤顺序
int CURRENT_STEP=0x00; //当前所处的CAN数据发送和接收的步骤,“接收线程“会根据”当前步骤”和“CAN数据内容”判断是否是正确响应
unsigned int Ecu_DialogId= 0x000; // ECU的CANID,每个ECU不一样
int Fun_Id = 0x7df; //功能寻址的CANID,固定值
DWORD seed0 =0; //UDS 0X27,ECU返回过来的seed第1位
DWORD seed1 =0; //UDS 0X27,ECU返回过来的seed第2位
DWORD seed2 =0; //UDS 0X27,ECU返回过来的seed第3位(若有)
DWORD seed3 =0; //UDS 0X27,ECU返回过来的seed第4位(若有)
DWORD seed0_tmp;
DWORD seed1_tmp;
DWORD seed2_tmp;
DWORD seed3_tmp;
DWORD seed;// UDS 0X27,ECU返回过来的seed
int Seedsize = 0; // UDS 0X27,ECU返回过来的seed位数,一般是2或者4
DWORD key_tmp;
DWORD key;   //UDS 0X27, 由seed计算出的key,两位或者四位,用于ECU安全解锁
int NoResCount=0; // 未接收响应的等待次数,超过一定数目应当认为测试失败,进入shutdown流程
int LogAllRecv =1; //接收数据是否全打印
int TESTMODE =1; //是否是测试模式,测试模式时,CAN1 CAN2直连。非测试模式时CAN2不使用。void *receive_func(void* param)  //接收线程。
{int reclen=0;VCI_CAN_OBJ rec[3000];//接收缓存,设为3000为佳。int i,j;int *run=(int*)param;//线程启动,退出控制。int ind_recv=0; //0: CAN1  1:CAN2while((*run)&0x0f){usleep(300000);//延时300ms。if((reclen=VCI_Receive(VCI_USBCAN2,0,ind_recv,rec,3000,100))>0)//调用接收函数,如果有数据,进行数据处理显示。{for(j=0;j<reclen;j++){if(LogAllRecv){printf("[RECV]Index:%04d  ",count);count++;//序号递增printf("CAN%d RX ID:0x%08X", ind_recv+1, rec[j].ID);//IDif(rec[j].ExternFlag==0) printf(" Standard ");//帧格式:标准帧if(rec[j].ExternFlag==1) printf(" Extend   ");//帧格式:扩展帧if(rec[j].RemoteFlag==0) printf(" Data   ");//帧类型:数据帧if(rec[j].RemoteFlag==1) printf(" Remote ");//帧类型:远程帧printf("DLC:0x%02X",rec[j].DataLen);//帧长度printf(" data:0x");    //数据        for(i = 0; i < rec[j].DataLen; i++){printf(" %02X", rec[j].Data[i]);}printf(" TimeStamp:0x%08X",rec[j].TimeStamp);//时间标识。printf("\n");}if(0X01 == CURRENT_STEP &&0 == rec[j].ExternFlag && 0x50 == rec[j].Data[1] && 0x03 == rec[j].Data[2]){printf("STEP[0X01] 03 diagConversation resp received!\n");STEP =0x07; //设置全局变量STEP指示下一步tester应该发送什么CAN消息}else if(0X07 == CURRENT_STEP && 0 == rec[j].ExternFlag && 0x06 == rec[j].Data[0]&& 0x67 == rec[j].Data[1] && 0x01 == rec[j].Data[2]){printf("STEP[0X07] ask seed resp 4 seeds received!\n");seed0 =  rec[j].Data[3];seed1 =  rec[j].Data[4];seed2 =  rec[j].Data[5];seed3 =  rec[j].Data[6];Seedsize = 4; //全局变量Seedsize指示,下一步发送CAN消息前应该组装多少位的keySTEP = 0X71; //设置全局变量STEP指示下一步tester应该发送什么CAN消息      }else if(0X07 ==CURRENT_STEP && 0 == rec[j].ExternFlag && 0x04 == rec[j].Data[0]&& 0x67 == rec[j].Data[1] && 0x01 == rec[j].Data[2]){printf("STEP[0X07] ask seed resp 2 seeds received!\n");seed0 =  rec[j].Data[3];seed1 =  rec[j].Data[4];Seedsize = 2;//全局变量Seedsize指示,下一步发送CAN消息前应该组装多少位的keySTEP = 0X71;     //设置全局变量STEP指示下一步tester应该发送什么CAN消息  }else if(0X71 == CURRENT_STEP && 0 == rec[j].ExternFlag && 0x67 == rec[j].Data[1] && 0x02 == rec[j].Data[2]){printf("STEP[0X71] send key resp received!\n");  STEP = 0x08;   //设置全局变量STEP指示下一步tester应该发送什么CAN消息      }else if(0X08 == CURRENT_STEP && 0 == rec[j].ExternFlag && 0x50 == rec[j].Data[1] && 0x02 == rec[j].Data[2]){printf("STEP[0X08] enter codeConversation resp received!\n");STEP =0x09;//设置全局变量STEP指示下一步tester应该发送什么CAN消息}else if(0X09 == CURRENT_STEP &&0 == rec[j].ExternFlag && 0x06 == rec[j].Data[0]&& 0x67 == rec[j].Data[1] && 0x01 == rec[j].Data[2]){printf("STEP[0X09] ask seed resp 4 seeds received!\n");seed0 =  rec[j].Data[3];seed1 =  rec[j].Data[4];seed2 =  rec[j].Data[5];seed3 =  rec[j].Data[6];Seedsize = 4;    //全局变量Seedsize指示,下一步发送CAN消息前应该组装多少位的key  STEP = 0x91;       //设置全局变量STEP指示下一步tester应该发送什么CAN消息  }else if(0X09 == CURRENT_STEP &&0 == rec[j].ExternFlag && 0x04 == rec[j].Data[0]&& 0x67 == rec[j].Data[1] && 0x01 == rec[j].Data[2]){printf("STEP[0X07] ask seed resp 2 seeds received!\n");seed0 =  rec[j].Data[3];seed1 =  rec[j].Data[4];Seedsize = 2;//全局变量Seedsize指示,下一步发送CAN消息前应该组装多少位的keySTEP = 0X91; //设置全局变量STEP指示下一步tester应该发送什么CAN消息      }else if(0X91 == CURRENT_STEP &&0 == rec[j].ExternFlag && 0x67 == rec[j].Data[1] && 0x02 == rec[j].Data[2]){printf("STEP[0X91] send key resp resp received!\n");          STEP = 0xFF;   //进入0xFF步骤表示测试成功,即将是进入结束流程       }}}     }printf("run thread exit\n");//退出接收线程 pthread_exit(0);
}int main(int argc, char *argv[])
{int i;for (i = 0; i < argc; i++){printf("argc = %d | argv[%d] %s\n", i, i, argv[i]);}
//解析输入参数    Ecu_DialogId ,并打印Ecu_DialogId = atoi(argv[1]);printf("Ecu_DialogId = 0x%04x\n",Ecu_DialogId);//设备信息打印    printf(">>this is hello !\r\n");//指示程序已运行num=VCI_FindUsbDevice2(pInfo1);printf(">>USBCAN DEVICE NUM:");printf("%d", num);printf(" PCS");printf("\n");for(int i=0;i<num;i++){printf("Device:");printf("%d", i);printf("\n");printf(">>Get VCI_ReadBoardInfo success!\n"); }if(VCI_OpenDevice(VCI_USBCAN2,0,0)==1)//打开设备{printf(">>open deivce success!\n");//打开设备成功}else{printf(">>open deivce error!\n");exit(1);}if(VCI_ReadBoardInfo(VCI_USBCAN2,0,&pInfo)==1)//读取设备序列号、版本等信息。{printf(">>Get VCI_ReadBoardInfo success!\n");   }else{printf(">>Get VCI_ReadBoardInfo error!\n");exit(1);}//初始化参数,严格参数二次开发函数库说明书。VCI_INIT_CONFIG config;config.AccCode= (Ecu_DialogId+8) << 21;printf("config.AccCode:%08X\n",config.AccCode); config.AccMask=0x00000000;//AccMask的值0x00000000表示所有位均为相关位,AccMask=0xFFFFFFFF表示都接收    config.Filter=1;//1:接收所有帧  2:只接收标准帧 3:只接收扩展帧 config.Timing0=0x00;/*波特率125 Kbps  0x03  0x1C ||| 波特率500 Kbps  0x00  0x1C*/config.Timing1=0x1C;config.Mode=0;//正常模式      //CAN1通道的初始化if(VCI_InitCAN(VCI_USBCAN2,0,0,&config)!=1){printf(">>Init CAN1 error\n");VCI_CloseDevice(VCI_USBCAN2,0);}if(VCI_StartCAN(VCI_USBCAN2,0,0)!=1){printf(">>Start CAN1 error\n");VCI_CloseDevice(VCI_USBCAN2,0);}
//在自测模式下,需要使用CAN2通道,所以进行CAN2通道初始化if(TESTMODE){if(VCI_InitCAN(VCI_USBCAN2,0,1,&config)!=1){printf(">>Init can2 error\n");VCI_CloseDevice(VCI_USBCAN2,0);}if(VCI_StartCAN(VCI_USBCAN2,0,1)!=1){printf(">>Start can2 error\n");VCI_CloseDevice(VCI_USBCAN2,0);}        }//创建接收线程,持续接收数据包int m_run0=1;pthread_t threadid;int ret;ret=pthread_create(&threadid,NULL,receive_func,&m_run0);//ID默认设置为CANID, 所有报文都是标准帧,默认填充字符是0x55VCI_CAN_OBJ send[1];while(1){//每次发送前报文初始化send[0].ID= Ecu_DialogId;send[0].SendType=0;send[0].RemoteFlag=0;send[0].ExternFlag=0;send[0].DataLen=8;for (i=0;i<8;i++){send[0].Data[i] = 0x55;}
//STEP0x00:还没有收到ECU回复
//step0x01:enter 03 diagConversation
//step0x07:ask seed
//step0x71:send key
//step0x08:enter codeConversation
//step0x09:ask seed
//step0x91:send key
//step0xFF:所有流程结束switch(STEP) //本switch-case里所有的发送都是通过CAN1通道{
//step0x01:enter 03 diagConversationcase 0x01://需要发送的帧,结构体设置send[0].Data[0] = 0x02;send[0].Data[1] = 0x10;send[0].Data[2] = 0x03;         if(VCI_Transmit(VCI_USBCAN2, 0, 0, send, 1) == 1){printf("STEP[0X%02x] enter 03 diagConversation SEND SUCCESS!Index:%04d   CAN1 TX ID:0x%08X data:0x",STEP,count,send[0].ID);count++;for(i=0;i<send[0].DataLen;i++){printf(" %02X",send[0].Data[i]);}printf("\n");}else{printf("STEP[%02x] VCI_Transmit failed!",STEP);goto SHUTDOWN;}CURRENT_STEP =STEP;//全局变量CURRENT_STEP是为了记录当前所处步骤(接收线程和自测时的模拟ECU需要这个变量)STEP = 0x00; //tester的CAN消息发送成功后将STEP设置为0x00是为了防止重复发送,也方便计算等待时间,长时间等待不到响应则判定测试失败usleep(200000);//延时200msbreak;
//step0x07:ask seedcase 0x07://需要发送的帧,结构体设置send[0].Data[0] = 0x02;send[0].Data[1] = 0x27;send[0].Data[2] = 0x01;if(VCI_Transmit(VCI_USBCAN2, 0, 0, send, 1) == 1){printf("STEP[0X%02x] ask seed SEND SUCCESS!Index:%04d   CAN1 TX ID:0x%08X data:0x",STEP,count,send[0].ID);count++;for(i=0;i<send[0].DataLen;i++){printf(" %02X",send[0].Data[i]);}printf("\n");}else{printf("STEP[%02x] VCI_Transmit failed!",STEP);goto SHUTDOWN;}CURRENT_STEP =STEP;//全局变量CURRENT_STEP是为了记录当前所处步骤(接收线程和自测时的模拟ECU需要这个变量)STEP = 0x00;//tester的CAN消息发送成功后将STEP设置为0x00是为了防止重复发送,也方便计算等待时间,长时间等待不到响应则判定测试失败usleep(300000);//延时300msbreak;
//step0x71:send keycase 0x71://需要发送的帧,结构体设置//Seedsize有2和4两种可能,分别采取不同的组装CAN报文的形式if(4 == Seedsize){ seed0_tmp = seed0 << 3*8;seed1_tmp = seed1 << 2*8;seed2_tmp = seed2 << 8;seed3_tmp = seed3;seed = seed0_tmp + seed1_tmp + seed2_tmp + seed3_tmp;printf("seed is  0x%08x\n",seed);key = seed;//汽车厂自定义安全解锁的算法,这里直接key=seed。printf("key is  0x%08x\n",key);send[0].Data[0] = 0x06;send[0].Data[1] = 0x27;send[0].Data[2] = 0x02;send[0].Data[3] = (key & 0xff000000) >> 3*8;send[0].Data[4]  = (key & 0x00ff0000) >> 2*8;send[0].Data[5] = (key & 0x0000ff00) >> 8;send[0].Data[6] = (key & 0x000000ff);         }else if(2 == Seedsize){seed0_tmp = seed0 << 1*8;seed1_tmp = seed1;seed = seed0_tmp + seed1_tmp;printf("seed is  0x%04x\n",seed);key_tmp = seed;//汽车厂自定义安全解锁的算法,这里直接key=seed。key = key_tmp & 0xffff;printf("key is  0x%04x\n",key );send[0].Data[0] = 0x04;send[0].Data[1] = 0x27;send[0].Data[2] = 0x02;send[0].Data[3] = (key & 0xff00) >> 1*8;send[0].Data[4]  = (key & 0x00ff);            }else{printf("Seedsize error!");goto SHUTDOWN;}if(VCI_Transmit(VCI_USBCAN2, 0, 0, send, 1) == 1){printf("STEP[0X%02x] send key SEND SUCCESS!Index:%04d   CAN1 TX ID:0x%08X data:0x",STEP,count,send[0].ID);count++;for(i=0;i<send[0].DataLen;i++){printf(" %02X",send[0].Data[i]);}printf("\n");}else{printf("STEP[%02x] VCI_Transmit failed!\n",STEP);goto SHUTDOWN;}CURRENT_STEP =STEP;//全局变量CURRENT_STEP是为了记录当前所处步骤(接收线程和自测时的模拟ECU需要这个变量)STEP = 0x00;//tester的CAN消息发送成功后将STEP设置为0x00是为了防止重复发送,也方便计算等待时间,长时间等待不到响应则判定测试失败usleep(500000);//延时500msbreak;
//step0x08:enter codeConversation           case 0x08://需要发送的帧,结构体设置 send[0].Data[0] = 0x02;send[0].Data[1] = 0x10;send[0].Data[2] = 0x02;if(VCI_Transmit(VCI_USBCAN2, 0, 0, send, 1) == 1){printf("STEP[0X%02x] enter codeConversationng SEND SUCCESS!Index:%04d   CAN1 TX ID:0x%08X data:0x",STEP,count,send[0].ID);count++;for(i=0;i<send[0].DataLen;i++){printf(" %02X",send[0].Data[i]);}printf("\n");}else{printf("STEP[%02x] VCI_Transmit failed!",STEP);goto SHUTDOWN;}CURRENT_STEP =STEP;//全局变量CURRENT_STEP是为了记录当前所处步骤(接收线程和自测时的模拟ECU需要这个变量)STEP = 0x00;//tester的CAN消息发送成功后将STEP设置为0x00是为了防止重复发送,也方便计算等待时间,长时间等待不到响应则判定测试失败usleep(500000);//延时500msbreak;
//step0x09:ask seedcase 0x09://需要发送的帧,结构体设置send[0].Data[0] = 0x02;send[0].Data[1] = 0x27;send[0].Data[2] = 0x01;if(VCI_Transmit(VCI_USBCAN2, 0, 0, send, 1) == 1){printf("STEP[0X%02x] ask seed SEND SUCCESS!Index:%04d   CAN1 TX ID:0x%08X data:0x",STEP,count,send[0].ID);count++;for(i=0;i<send[0].DataLen;i++){printf(" %02X",send[0].Data[i]);}printf("\n");}else{printf("STEP[%02x] VCI_Transmit failed!",STEP);goto SHUTDOWN;}CURRENT_STEP =STEP;//全局变量CURRENT_STEP是为了记录当前所处步骤(接收线程和自测时的模拟ECU需要这个变量)STEP = 0x00;//tester的CAN消息发送成功后将STEP设置为0x00是为了防止重复发送,也方便计算等待时间,长时间等待不到响应则判定测试失败usleep(500000);//延时500msbreak;
//step0x91:send keycase 0x91://需要发送的帧,结构体设置//Seedsize有2和4两种可能,分别采取不同的组装CAN报文的形式if(4 == Seedsize){ seed0_tmp = seed0 << 3*8;seed1_tmp = seed1 << 2*8;seed2_tmp = seed2 << 8;seed3_tmp = seed3;seed = seed0_tmp + seed1_tmp + seed2_tmp + seed3_tmp;printf("seed is  0x%08x\n",seed);key = seed;//汽车厂自定义安全解锁的算法,这里直接key=seed。printf("key is  0x%08x\n",key);send[0].Data[0] = 0x06;send[0].Data[1] = 0x27;send[0].Data[2] = 0x02;send[0].Data[3] = (key & 0xff000000) >> 3*8;send[0].Data[4]  = (key & 0x00ff0000) >> 2*8;send[0].Data[5] = (key & 0x0000ff00) >> 8;send[0].Data[6] = (key & 0x000000ff);         }else if(2 == Seedsize){seed0_tmp = seed0 << 1*8;seed1_tmp = seed1;seed = seed0_tmp + seed1_tmp;printf("seed is  0x%04x\n",seed);key_tmp = seed;//汽车厂自定义安全解锁的算法,这里直接key=seed。key = key_tmp & 0xffff;printf("key is  0x%04x\n",key );send[0].Data[0] = 0x04;send[0].Data[1] = 0x27;send[0].Data[2] = 0x02;send[0].Data[3] = (key & 0xff00) >> 1*8;send[0].Data[4]  = (key & 0x00ff);            }else{printf("Seedsize error!");goto SHUTDOWN;}if(VCI_Transmit(VCI_USBCAN2, 0, 0, send, 1) == 1){printf("STEP[0X%02x] send key SEND SUCCESS!Index:%04d   CAN1 TX ID:0x%08X data:0x",STEP,count,send[0].ID);count++;for(i=0;i<send[0].DataLen;i++){printf(" %02X",send[0].Data[i]);}printf("\n");}else{printf("STEP[%02x] VCI_Transmit failed!\n",STEP);goto SHUTDOWN;}CURRENT_STEP =STEP;//全局变量CURRENT_STEP是为了记录当前所处步骤(接收线程和自测时的模拟ECU需要这个变量)STEP = 0x00;//tester的CAN消息发送成功后将STEP设置为0x00是为了防止重复发送,也方便计算等待时间,长时间等待不到响应则判定测试失败usleep(500000);//延时500msbreak;       case 0x00://还没有收到ECU回复printf("[WAITING RESPONSE]VCI_Receive have not found corresponding ECU response!\n");if(NoResCount < NO_RES_COUNT_MAX){NoResCount++;}else{printf("VCI_Receive have not found corresponding ECU response > %d times,test failed!!!",NO_RES_COUNT_MAX);goto SHUTDOWN;               }   usleep(1000000);//延时1000msbreak;
//step0xFF:所有流程结束case 0xFF://所有流程结束printf("VCI_Receive have found all corresponding ECU response!\n test SUCESS!!!\n");goto SHUTDOWN;break;default:printf("unknown step\n");goto SHUTDOWN;}
// 自测模式下,以下代码用于CAN2通道模仿ECU给tester回复if(TESTMODE){ switch(CURRENT_STEP)//根据当前所处步骤决定ECU模拟器回复什么消息,本switch-case里所有的发送都是通过CAN2通道{case 0x01://需要发送的帧,结构体设置send[0].ID= Ecu_DialogId +8; //ECU的响应报文的CANID时ECU_DialogId加8send[0].SendType=0;send[0].RemoteFlag=0;send[0].ExternFlag=0;send[0].DataLen=8;      send[0].Data[0] = 0x06;send[0].Data[1] = 0x50;send[0].Data[2] = 0x03;send[0].Data[3] = 0x00;send[0].Data[4] = 0x32;send[0].Data[5] = 0x01;send[0].Data[6] = 0xf4;send[0].Data[7] = 0xaa;    if(VCI_Transmit(VCI_USBCAN2, 0, 1, send, 1) == 1){}else{printf("STEP[%02x] VCI_Transmit failed!",STEP);goto SHUTDOWN;}usleep(300000);//延时300msbreak;case 0x07://需要发送的帧,结构体设置send[0].ID= Ecu_DialogId + 8;send[0].SendType=0;send[0].RemoteFlag=0;send[0].ExternFlag=0;send[0].DataLen=8;if(0)//设为1,表示seedsize 4, 0表示seedsize2{send[0].Data[0] = 0x06;send[0].Data[1] = 0x67;send[0].Data[2] = 0x01;send[0].Data[3] = 0x88;send[0].Data[4] = 0x88;send[0].Data[5] = 0x88;send[0].Data[6] = 0x88;send[0].Data[7] = 0xaa;                  }               else{send[0].Data[0] = 0x04;send[0].Data[1] = 0x67;send[0].Data[2] = 0x01;send[0].Data[3] = 0x88;send[0].Data[4] = 0x88;send[0].Data[5] = 0xaa;send[0].Data[6] = 0xaa;send[0].Data[7] = 0xaa;               }if(VCI_Transmit(VCI_USBCAN2, 0, 1, send, 1) == 1){}else{printf("STEP[%02x] VCI_Transmit failed!",STEP);goto SHUTDOWN;}usleep(300000);//延时300msbreak;case 0x71://需要发送的帧,结构体设置send[0].ID= Ecu_DialogId + 8;send[0].SendType=0;send[0].RemoteFlag=0;send[0].ExternFlag=0;send[0].DataLen=8;          send[0].Data[0] = 0x02;send[0].Data[1] = 0x67;send[0].Data[2] = 0x02;send[0].Data[3] = 0xaa;send[0].Data[4] = 0xaa;send[0].Data[5] = 0xaa;send[0].Data[6] = 0xaa;send[0].Data[7] = 0xaa;    if(VCI_Transmit(VCI_USBCAN2, 0, 1, send, 1) == 1){}else{printf("STEP[%02x] VCI_Transmit failed!",STEP);goto SHUTDOWN;}usleep(300000);//延时300msbreak;case 0x08://需要发送的帧,结构体设置send[0].ID= Ecu_DialogId + 8;send[0].SendType=0;send[0].RemoteFlag=0;send[0].ExternFlag=0;send[0].DataLen=8;   send[0].Data[0] = 0x06;send[0].Data[1] = 0x50;send[0].Data[2] = 0x02;send[0].Data[3] = 0x00;send[0].Data[4] = 0x32;send[0].Data[5] = 0x01;send[0].Data[6] = 0xf4;send[0].Data[7] = 0x00;    if(VCI_Transmit(VCI_USBCAN2, 0, 1, send, 1) == 1){}else{printf("STEP[%02x] VCI_Transmit failed!",STEP);goto SHUTDOWN;}usleep(300000);//延时300msbreak;case 0x09://需要发送的帧,结构体设置send[0].ID= Ecu_DialogId + 8;send[0].SendType=0;send[0].RemoteFlag=0;send[0].ExternFlag=0;send[0].DataLen=8;if(1)//设为1,表示seedsize 4, 0表示seedsize2{send[0].Data[0] = 0x06;send[0].Data[1] = 0x67;send[0].Data[2] = 0x01;send[0].Data[3] = 0x88;send[0].Data[4] = 0x88;send[0].Data[5] = 0x88;send[0].Data[6] = 0x88;send[0].Data[7] = 0xaa;                  }               else{send[0].Data[0] = 0x04;send[0].Data[1] = 0x67;send[0].Data[2] = 0x01;send[0].Data[3] = 0x88;send[0].Data[4] = 0x88;send[0].Data[5] = 0xaa;send[0].Data[6] = 0xaa;send[0].Data[7] = 0xaa;               }   if(VCI_Transmit(VCI_USBCAN2, 0, 1, send, 1) == 1){}else{printf("STEP[%02x] VCI_Transmit failed!",STEP);goto SHUTDOWN;}usleep(300000);//延时300msbreak;
//step0x91:send keycase 0x91://需要发送的帧,结构体设置send[0].ID= Ecu_DialogId + 8;send[0].SendType=0;send[0].RemoteFlag=0;send[0].ExternFlag=0;send[0].DataLen=8;    send[0].Data[0] = 0x02;send[0].Data[1] = 0x67;send[0].Data[2] = 0x02;send[0].Data[3] = 0xaa;send[0].Data[4] = 0xaa;send[0].Data[5] = 0xaa;send[0].Data[6] = 0xaa;send[0].Data[7] = 0xaa;    if(VCI_Transmit(VCI_USBCAN2, 0, 1, send, 1) == 1){}else{printf("STEP[%02x] VCI_Transmit failed!",STEP);goto SHUTDOWN;}usleep(300000);//延时300msbreak;default:printf("unknown CAN2 step:%02X\n",CURRENT_STEP);goto SHUTDOWN;}}}// while endSHUTDOWN:m_run0=0;//线程关闭指令。pthread_join(threadid,NULL);//等待线程关闭。usleep(100000);//延时100ms。//VCI_ResetCAN(VCI_USBCAN2, 0, 0);//复位CAN1通道。usleep(100000);//延时100ms。//VCI_CloseDevice(VCI_USBCAN2,0);//关闭设备。//除收发函数外,其它的函数调用前后,最好加个毫秒级的延时,即不影响程序的运行,又可以让USBCAN设备有充分的时间处理指令。//goto ext;
}

代码执行结果:

└─# ./hello_cpp 1800
argc = 0 | argv[0] ./hello_cpp
argc = 1 | argv[1] 1800
Ecu_DialogId = 0x0708
>>this is hello !
>>USBCAN DEVICE NUM:1 PCS
Device:0
>>Get VCI_ReadBoardInfo success!
>>open deivce success!
>>Get VCI_ReadBoardInfo success!
config.AccCode:E2000000
STEP[0X01] enter 03 diagConversation SEND SUCCESS!Index:0000   CAN1 TX ID:0x00000708 data:0x 02 10 03 55 55 55 55 55
[RECV]Index:0001  CAN1 RX ID:0x00000710 Standard  Data   DLC:0x08 data:0x 06 50 03 00 32 01 F4 AA TimeStamp:0x0033A452
STEP[0X01] 03 diagConversation resp received!
STEP[0X07] ask seed SEND SUCCESS!Index:0002   CAN1 TX ID:0x00000708 data:0x 02 27 01 55 55 55 55 55
[RECV]Index:0003  CAN1 RX ID:0x00000710 Standard  Data   DLC:0x08 data:0x 04 67 01 88 88 AA AA AA TimeStamp:0x0033BC1C
STEP[0X07] ask seed resp 2 seeds received!
seed is  0x8888
key is  0x8888
STEP[0X71] send key SEND SUCCESS!Index:0004   CAN1 TX ID:0x00000708 data:0x 04 27 02 88 88 55 55 55
[RECV]Index:0005  CAN1 RX ID:0x00000710 Standard  Data   DLC:0x08 data:0x 02 67 02 AA AA AA AA AA TimeStamp:0x0033DC85
STEP[0X71] send key resp received!
STEP[0X08] enter codeConversationng SEND SUCCESS!Index:0006   CAN1 TX ID:0x00000708 data:0x 02 10 02 55 55 55 55 55
[RECV]Index:0007  CAN1 RX ID:0x00000710 Standard  Data   DLC:0x08 data:0x 06 50 02 00 32 01 F4 00 TimeStamp:0x0033FC21
STEP[0X08] enter codeConversation resp received!
STEP[0X09] ask seed SEND SUCCESS!Index:0008   CAN1 TX ID:0x00000708 data:0x 02 27 01 55 55 55 55 55
[RECV]Index:0009  CAN1 RX ID:0x00000710 Standard  Data   DLC:0x08 data:0x 06 67 01 88 88 88 88 AA TimeStamp:0x00341BC1
STEP[0X09] ask seed resp 4 seeds received!
seed is  0x88888888
key is  0x88888888
STEP[0X91] send key SEND SUCCESS!Index:0010   CAN1 TX ID:0x00000708 data:0x 06 27 02 88 88 88 88 55
[RECV]Index:0011  CAN1 RX ID:0x00000710 Standard  Data   DLC:0x08 data:0x 02 67 02 AA AA AA AA AA TimeStamp:0x00343B93
STEP[0X91] send key resp resp received!
VCI_Receive have found all corresponding ECU response!test SUCESS!!!
run thread exit

3. 总结

这款CAN分析仪性价比不错,功能也够强大,如果你想使用,可以参考本博客试试。

CANanlystII 基于linux的二次开发实践相关推荐

  1. CANanlystII 基于python的二次开发实践

    前期,我已经编写过一篇<CANanlystII 基于linux的二次开发实践>这篇博客承接上一篇博客,所以背景知识和测试场景,就不再赘述. 背景知识和测试场景,可以查阅如下: CANanl ...

  2. 据说这是熟练掌握python的爷们_dongbei 是一门基于 Python 3 二次开发的东北方言编程语言...

    dongbei - 东北方言编程语言 学编程,就整东北浪! 体格咋地 扫码关注原作者微信公众号"老万故事会": 引言 dongbei是啥?它是一门以东北方言词汇为基本关键字的以人为 ...

  3. 《Linux C/C++服务器开发实践》简介

    #好书推荐##好书奇遇季#Linux网络服务器编程入门书<Linux C/C++服务器开发实践>,京东当当天猫都有发售.416页厚书,定价99元,打折一下更便宜. 本书从五大服务器编程基础 ...

  4. 《Flask Web开发——基于Python的Web应用开发实践》一字一句上机实践(上)

    目录 前言 第1章 安装 第2章 程序的基本结构 第3章 模板 第4章 Web表单 第5章 数据库 第6章 电子邮件 第7章 大型程序的结构 前言 学习Python也有一个半月时间了,学到现在感觉还是 ...

  5. 海康Camera MVS Linux SDK二次开发封装ROS packge过程记录(c++)

    Livox Lidar  + HIKROBOT Camera系列 最近在开发相机和激光雷达融合的slam算法,主要用于三维重建,想实时的得到彩色点云地图,传感器选择了海康威视的工业相机和大疆的固态激光 ...

  6. java二次开发浏览器内核_深入理解基于Selenium的二次开发

    对于做web端自动化测试的人来说,可能接触selenium比QTP还要多,但是我们在做基于selenium的二次开发的时候,经常会说到二次开发是 为了易于维护,很多人可能不懂得维护的价值是什么,和到底 ...

  7. Vue+Vant 基于DatetimePicker进行二次开发,实现yyyyMMdd hh:mm:ss时间选择

    Vue+Vant 基于DatetimePicker进行二次开发,实现yyyyMMdd hh:mm:ss时间选择 1.效果图 2.前提 3.项目结构 4.index.vue 5.timeSelectio ...

  8. 基于Visio的二次开发

    基于Visio的二次开发 前一段时间,由于项目的需要:学习了一些关于Visio二次开发的知识:现在工具基本成形了,也算告一段落了:因此想总结一下关于Visio的二次开发的一些基本知识: 对于基于Vis ...

  9. WordPress主题 Vieu主题V4.5无授权无限制版 基于Dux主题二次开发 完美运行

    模板简介: WordPress主题vieu基于Dux主题二次开发!的一款专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板.适用范围:wordpress主题.WordPres ...

最新文章

  1. 【CV】吴恩达机器学习课程笔记第10章
  2. 【课件】基础雷达信号处理
  3. mysql 5.6 删除用户_mysql 新增 删除用户和权限分配
  4. web前端零基础入门学习!前端真不难!
  5. IP Cam须改原厂密码防黑客
  6. c语言怎么让图形界面单独显示,「分享」C语言如何编写图形界面
  7. 重新leetcode第2天——递归讲解合集
  8. 包含min函数的栈 【微软面试100题 第二题】
  9. readonly strong nonatomic 和IBOutlet
  10. wordpress配置HTTPS遇到问题解决方案
  11. 东芝300D粉盒清零
  12. Go Grpc Jwt身份认证和Gateway集成以及HTTPS双向认证
  13. ES6(ECMAScript6)知识总结(二)
  14. win10计算机控制面板在哪里,教您win10控制面板在哪
  15. char和数值的类型转换
  16. 一文掌握华为全过程项目管理的方法步骤和具体动作【墙裂推荐】
  17. 二进制视频数据常见标志位
  18. mapbox-gl加载气象场数据(视频)
  19. 记:某次关于均方根与均值的讨论心得
  20. 1999-2021地级市GDP及一二三产业GDP数据

热门文章

  1. Excel批量更改文件名
  2. 【C语言】深度探索offsetof,解析结构体的成员数组和指针
  3. 读了这篇文章,你将变身web分析大师
  4. CTreeCtrl::InsertItem给树形视图控件添加一个项目
  5. 谷歌出品的Web打包方案:Web Bundles 技术揭秘
  6. 【Java开发】Spring Cloud 10 :Stream消息驱动
  7. 某直播平台协议分析之一
  8. 国泰君安 191 Alpha 因子的流批一体实现
  9. 废旧电子元件提炼黄金树脂
  10. 实时天气api, API接口调用实况天气 2019