• CANanlystII 基于linux的二次开发实践


    1. USBCAN分析仪国内现状

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

    2. 创芯科技产品

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

    2.1 设备自测

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

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

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

    执行自测用例

    1. root@zyy-VirtualBox:/home/zyy/controlcan# ls
    2. controlcan.h hello_cpp libcontrolcan.so main_bak.cpp main.cpp Makefile
    3. root@zyy-VirtualBox:/home/zyy/controlcan# rm -r hello_cpp
    4. root@zyy-VirtualBox:/home/zyy/controlcan# make clean
    5. rm -f *.o hello
    6. root@zyy-VirtualBox:/home/zyy/controlcan# make
    7. g++ -o hello_cpp main.cpp /home/zyy/controlcan/libcontrolcan.so -lpthread
    8. root@zyy-VirtualBox:/home/zyy/controlcan1# ./hello_cpp
    9. >>this is hello !
    10. >>USBCAN DEVICE NUM:1 PCS
    11. Device:0
    12. >>Get VCI_ReadBoardInfo success!
    13. >>Serial_Num:31F100016D6
    14. >>hw_Type:CAN-Linux
    15. >>Firmware Version:V3.40
    16. >>
    17. >>
    18. >>
    19. >>open deivce success!
    20. >>Get VCI_ReadBoardInfo success!
    21. >>Serial_Num:31F100016D6
    22. >>hw_Type:CAN-Linux
    23. >>Firmware Version:V3.40
    24. Index:0000 CAN1 TX ID:0x00000000 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07
    25. Index:0001 CAN2 TX ID:0x00000001 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07
    26. Index:0002 CAN2 RX ID:0x00000000 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D81E
    27. Index:0003 CAN1 TX ID:0x00000002 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07
    28. Index:0004 CAN1 RX ID:0x00000001 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D85C
    29. Index:0005 CAN2 TX ID:0x00000003 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07
    30. Index:0006 CAN2 RX ID:0x00000002 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D890
    31. Index:0007 CAN1 TX ID:0x00000004 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07
    32. Index:0008 CAN1 RX ID:0x00000003 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D8B6
    33. Index:0009 CAN2 TX ID:0x00000005 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07
    34. Index:0010 CAN2 RX ID:0x00000004 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D8E8
    35. Index:0011 CAN1 TX ID:0x00000006 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07
    36. Index:0012 CAN1 RX ID:0x00000005 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D912
    37. Index:0013 CAN2 TX ID:0x00000007 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07
    38. Index:0014 CAN2 RX ID:0x00000006 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D93D
    39. Index:0015 CAN1 TX ID:0x00000008 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07
    40. Index:0016 CAN1 RX ID:0x00000007 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D96F
    41. Index:0017 CAN2 TX ID:0x00000009 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07
    42. Index:0018 CAN2 RX ID:0x00000008 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D99F
    43. Index:0019 CAN1 RX ID:0x00000009 Extend Data DLC:0x08 data:0x 00 01 02 03 04 05 06 07 TimeStamp:0x0009D9DC
    44. 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博客

    编写代码如下:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include "controlcan.h"
    7. #include
    8. #include
    9. #include "unistd.h"
    10. #define NO_RES_COUNT_MAX 10 //等待响应的时间(周期)上限
    11. VCI_BOARD_INFO pInfo;//用来获取设备信息。
    12. int count=0;//数据列表中,用来存储列表序号。
    13. VCI_BOARD_INFO pInfo1 [50];
    14. int num=0;
    15. //重要全局变量
    16. //int i;
    17. int STEP=0X01; //CAN数据发送和接收的步骤,用于控制步骤顺序
    18. int CURRENT_STEP=0x00; //当前所处的CAN数据发送和接收的步骤,“接收线程“会根据”当前步骤”和“CAN数据内容”判断是否是正确响应
    19. unsigned int Ecu_DialogId= 0x000; // ECU的CANID,每个ECU不一样
    20. int Fun_Id = 0x7df; //功能寻址的CANID,固定值
    21. DWORD seed0 =0; //UDS 0X27,ECU返回过来的seed第1位
    22. DWORD seed1 =0; //UDS 0X27,ECU返回过来的seed第2位
    23. DWORD seed2 =0; //UDS 0X27,ECU返回过来的seed第3位(若有)
    24. DWORD seed3 =0; //UDS 0X27,ECU返回过来的seed第4位(若有)
    25. DWORD seed0_tmp;
    26. DWORD seed1_tmp;
    27. DWORD seed2_tmp;
    28. DWORD seed3_tmp;
    29. DWORD seed;// UDS 0X27,ECU返回过来的seed
    30. int Seedsize = 0; // UDS 0X27,ECU返回过来的seed位数,一般是2或者4
    31. DWORD key_tmp;
    32. DWORD key; //UDS 0X27, 由seed计算出的key,两位或者四位,用于ECU安全解锁
    33. int NoResCount=0; // 未接收响应的等待次数,超过一定数目应当认为测试失败,进入shutdown流程
    34. int LogAllRecv =1; //接收数据是否全打印
    35. int TESTMODE =1; //是否是测试模式,测试模式时,CAN1 CAN2直连。非测试模式时CAN2不使用。
    36. void *receive_func(void* param) //接收线程。
    37. {
    38. int reclen=0;
    39. VCI_CAN_OBJ rec[3000];//接收缓存,设为3000为佳。
    40. int i,j;
    41. int *run=(int*)param;//线程启动,退出控制。
    42. int ind_recv=0; //0: CAN1 1:CAN2
    43. while((*run)&0x0f)
    44. {
    45. usleep(300000);//延时300ms。
    46. if((reclen=VCI_Receive(VCI_USBCAN2,0,ind_recv,rec,3000,100))>0)//调用接收函数,如果有数据,进行数据处理显示。
    47. {
    48. for(j=0;j
    49. {
    50. if(LogAllRecv)
    51. {
    52. printf("[RECV]Index:%04d ",count);count++;//序号递增
    53. printf("CAN%d RX ID:0x%08X", ind_recv+1, rec[j].ID);//ID
    54. if(rec[j].ExternFlag==0) printf(" Standard ");//帧格式:标准帧
    55. if(rec[j].ExternFlag==1) printf(" Extend ");//帧格式:扩展帧
    56. if(rec[j].RemoteFlag==0) printf(" Data ");//帧类型:数据帧
    57. if(rec[j].RemoteFlag==1) printf(" Remote ");//帧类型:远程帧
    58. printf("DLC:0x%02X",rec[j].DataLen);//帧长度
    59. printf(" data:0x"); //数据
    60. for(i = 0; i < rec[j].DataLen; i++)
    61. {
    62. printf(" %02X", rec[j].Data[i]);
    63. }
    64. printf(" TimeStamp:0x%08X",rec[j].TimeStamp);//时间标识。
    65. printf("\n");
    66. }
    67. if(0X01 == CURRENT_STEP &&0 == rec[j].ExternFlag && 0x50 == rec[j].Data[1] && 0x03 == rec[j].Data[2])
    68. {
    69. printf("STEP[0X01] 03 diagConversation resp received!\n");
    70. STEP =0x07; //设置全局变量STEP指示下一步tester应该发送什么CAN消息
    71. }
    72. else if(0X07 == CURRENT_STEP && 0 == rec[j].ExternFlag && 0x06 == rec[j].Data[0]&& 0x67 == rec[j].Data[1] && 0x01 == rec[j].Data[2])
    73. {
    74. printf("STEP[0X07] ask seed resp 4 seeds received!\n");
    75. seed0 = rec[j].Data[3];
    76. seed1 = rec[j].Data[4];
    77. seed2 = rec[j].Data[5];
    78. seed3 = rec[j].Data[6];
    79. Seedsize = 4; //全局变量Seedsize指示,下一步发送CAN消息前应该组装多少位的key
    80. STEP = 0X71; //设置全局变量STEP指示下一步tester应该发送什么CAN消息
    81. }
    82. else if(0X07 ==CURRENT_STEP && 0 == rec[j].ExternFlag && 0x04 == rec[j].Data[0]&& 0x67 == rec[j].Data[1] && 0x01 == rec[j].Data[2])
    83. {
    84. printf("STEP[0X07] ask seed resp 2 seeds received!\n");
    85. seed0 = rec[j].Data[3];
    86. seed1 = rec[j].Data[4];
    87. Seedsize = 2;//全局变量Seedsize指示,下一步发送CAN消息前应该组装多少位的key
    88. STEP = 0X71; //设置全局变量STEP指示下一步tester应该发送什么CAN消息
    89. }
    90. else if(0X71 == CURRENT_STEP && 0 == rec[j].ExternFlag && 0x67 == rec[j].Data[1] && 0x02 == rec[j].Data[2])
    91. {
    92. printf("STEP[0X71] send key resp received!\n");
    93. STEP = 0x08; //设置全局变量STEP指示下一步tester应该发送什么CAN消息
    94. }
    95. else if(0X08 == CURRENT_STEP && 0 == rec[j].ExternFlag && 0x50 == rec[j].Data[1] && 0x02 == rec[j].Data[2])
    96. {
    97. printf("STEP[0X08] enter codeConversation resp received!\n");
    98. STEP =0x09;//设置全局变量STEP指示下一步tester应该发送什么CAN消息
    99. }
    100. else if(0X09 == CURRENT_STEP &&0 == rec[j].ExternFlag && 0x06 == rec[j].Data[0]&& 0x67 == rec[j].Data[1] && 0x01 == rec[j].Data[2])
    101. {
    102. printf("STEP[0X09] ask seed resp 4 seeds received!\n");
    103. seed0 = rec[j].Data[3];
    104. seed1 = rec[j].Data[4];
    105. seed2 = rec[j].Data[5];
    106. seed3 = rec[j].Data[6];
    107. Seedsize = 4; //全局变量Seedsize指示,下一步发送CAN消息前应该组装多少位的key
    108. STEP = 0x91; //设置全局变量STEP指示下一步tester应该发送什么CAN消息
    109. }
    110. else if(0X09 == CURRENT_STEP &&0 == rec[j].ExternFlag && 0x04 == rec[j].Data[0]&& 0x67 == rec[j].Data[1] && 0x01 == rec[j].Data[2])
    111. {
    112. printf("STEP[0X07] ask seed resp 2 seeds received!\n");
    113. seed0 = rec[j].Data[3];
    114. seed1 = rec[j].Data[4];
    115. Seedsize = 2;//全局变量Seedsize指示,下一步发送CAN消息前应该组装多少位的key
    116. STEP = 0X91; //设置全局变量STEP指示下一步tester应该发送什么CAN消息
    117. }
    118. else if(0X91 == CURRENT_STEP &&0 == rec[j].ExternFlag && 0x67 == rec[j].Data[1] && 0x02 == rec[j].Data[2])
    119. {
    120. printf("STEP[0X91] send key resp resp received!\n");
    121. STEP = 0xFF; //进入0xFF步骤表示测试成功,即将是进入结束流程
    122. }
    123. }
    124. }
    125. }
    126. printf("run thread exit\n");//退出接收线程
    127. pthread_exit(0);
    128. }
    129. int main(int argc, char *argv[])
    130. {
    131. int i;
    132. for (i = 0; i < argc; i++)
    133. {
    134. printf("argc = %d | argv[%d] %s\n", i, i, argv[i]);
    135. }
    136. //解析输入参数 Ecu_DialogId ,并打印
    137. Ecu_DialogId = atoi(argv[1]);
    138. printf("Ecu_DialogId = 0x%04x\n",Ecu_DialogId);
    139. //设备信息打印
    140. printf(">>this is hello !\r\n");//指示程序已运行
    141. num=VCI_FindUsbDevice2(pInfo1);
    142. printf(">>USBCAN DEVICE NUM:");printf("%d", num);printf(" PCS");printf("\n");
    143. for(int i=0;i
    144. {
    145. printf("Device:");printf("%d", i);printf("\n");
    146. printf(">>Get VCI_ReadBoardInfo success!\n");
    147. }
    148. if(VCI_OpenDevice(VCI_USBCAN2,0,0)==1)//打开设备
    149. {
    150. printf(">>open deivce success!\n");//打开设备成功
    151. }
    152. else
    153. {
    154. printf(">>open deivce error!\n");
    155. exit(1);
    156. }
    157. if(VCI_ReadBoardInfo(VCI_USBCAN2,0,&pInfo)==1)//读取设备序列号、版本等信息。
    158. {
    159. printf(">>Get VCI_ReadBoardInfo success!\n");
    160. }
    161. else
    162. {
    163. printf(">>Get VCI_ReadBoardInfo error!\n");
    164. exit(1);
    165. }
    166. //初始化参数,严格参数二次开发函数库说明书。
    167. VCI_INIT_CONFIG config;
    168. config.AccCode= (Ecu_DialogId+8) << 21;
    169. printf("config.AccCode:%08X\n",config.AccCode);
    170. config.AccMask=0x00000000;//AccMask的值0x00000000表示所有位均为相关位,AccMask=0xFFFFFFFF表示都接收
    171. config.Filter=1;//1:接收所有帧 2:只接收标准帧 3:只接收扩展帧
    172. config.Timing0=0x00;/*波特率125 Kbps 0x03 0x1C ||| 波特率500 Kbps 0x00 0x1C*/
    173. config.Timing1=0x1C;
    174. config.Mode=0;//正常模式
    175. //CAN1通道的初始化
    176. if(VCI_InitCAN(VCI_USBCAN2,0,0,&config)!=1)
    177. {
    178. printf(">>Init CAN1 error\n");
    179. VCI_CloseDevice(VCI_USBCAN2,0);
    180. }
    181. if(VCI_StartCAN(VCI_USBCAN2,0,0)!=1)
    182. {
    183. printf(">>Start CAN1 error\n");
    184. VCI_CloseDevice(VCI_USBCAN2,0);
    185. }
    186. //在自测模式下,需要使用CAN2通道,所以进行CAN2通道初始化
    187. if(TESTMODE)
    188. {
    189. if(VCI_InitCAN(VCI_USBCAN2,0,1,&config)!=1)
    190. {
    191. printf(">>Init can2 error\n");
    192. VCI_CloseDevice(VCI_USBCAN2,0);
    193. }
    194. if(VCI_StartCAN(VCI_USBCAN2,0,1)!=1)
    195. {
    196. printf(">>Start can2 error\n");
    197. VCI_CloseDevice(VCI_USBCAN2,0);
    198. }
    199. }
    200. //创建接收线程,持续接收数据包
    201. int m_run0=1;
    202. pthread_t threadid;
    203. int ret;
    204. ret=pthread_create(&threadid,NULL,receive_func,&m_run0);
    205. //ID默认设置为CANID, 所有报文都是标准帧,默认填充字符是0x55
    206. VCI_CAN_OBJ send[1];
    207. while(1)
    208. {
    209. //每次发送前报文初始化
    210. send[0].ID= Ecu_DialogId;
    211. send[0].SendType=0;
    212. send[0].RemoteFlag=0;
    213. send[0].ExternFlag=0;
    214. send[0].DataLen=8;
    215. for (i=0;i<8;i++)
    216. {
    217. send[0].Data[i] = 0x55;
    218. }
    219. //STEP0x00:还没有收到ECU回复
    220. //step0x01:enter 03 diagConversation
    221. //step0x07:ask seed
    222. //step0x71:send key
    223. //step0x08:enter codeConversation
    224. //step0x09:ask seed
    225. //step0x91:send key
    226. //step0xFF:所有流程结束
    227. switch(STEP) //本switch-case里所有的发送都是通过CAN1通道
    228. {
    229. //step0x01:enter 03 diagConversation
    230. case 0x01:
    231. //需要发送的帧,结构体设置
    232. send[0].Data[0] = 0x02;
    233. send[0].Data[1] = 0x10;
    234. send[0].Data[2] = 0x03;
    235. if(VCI_Transmit(VCI_USBCAN2, 0, 0, send, 1) == 1)
    236. {
    237. printf("STEP[0X%02x] enter 03 diagConversation SEND SUCCESS!Index:%04d CAN1 TX ID:0x%08X data:0x",STEP,count,send[0].ID);
    238. count++;
    239. for(i=0;i0].DataLen;i++)
    240. {
    241. printf(" %02X",send[0].Data[i]);
    242. }
    243. printf("\n");
    244. }
    245. else
    246. {
    247. printf("STEP[%02x] VCI_Transmit failed!",STEP);
    248. goto SHUTDOWN;
    249. }
    250. CURRENT_STEP =STEP;//全局变量CURRENT_STEP是为了记录当前所处步骤(接收线程和自测时的模拟ECU需要这个变量)
    251. STEP = 0x00; //tester的CAN消息发送成功后将STEP设置为0x00是为了防止重复发送,也方便计算等待时间,长时间等待不到响应则判定测试失败
    252. usleep(200000);//延时200ms
    253. break;
    254. //step0x07:ask seed
    255. case 0x07:
    256. //需要发送的帧,结构体设置
    257. send[0].Data[0] = 0x02;
    258. send[0].Data[1] = 0x27;
    259. send[0].Data[2] = 0x01;
    260. if(VCI_Transmit(VCI_USBCAN2, 0, 0, send, 1) == 1)
    261. {
    262. printf("STEP[0X%02x] ask seed SEND SUCCESS!Index:%04d CAN1 TX ID:0x%08X data:0x",STEP,count,send[0].ID);
    263. count++;
    264. for(i=0;i0].DataLen;i++)
    265. {
    266. printf(" %02X",send[0].Data[i]);
    267. }
    268. printf("\n");
    269. }
    270. else
    271. {
    272. printf("STEP[%02x] VCI_Transmit failed!",STEP);
    273. goto SHUTDOWN;
    274. }
    275. CURRENT_STEP =STEP;//全局变量CURRENT_STEP是为了记录当前所处步骤(接收线程和自测时的模拟ECU需要这个变量)
    276. STEP = 0x00;//tester的CAN消息发送成功后将STEP设置为0x00是为了防止重复发送,也方便计算等待时间,长时间等待不到响应则判定测试失败
    277. usleep(300000);//延时300ms
    278. break;
    279. //step0x71:send key
    280. case 0x71:
    281. //需要发送的帧,结构体设置
    282. //Seedsize有2和4两种可能,分别采取不同的组装CAN报文的形式
    283. if(4 == Seedsize)
    284. {
    285. seed0_tmp = seed0 << 3*8;
    286. seed1_tmp = seed1 << 2*8;
    287. seed2_tmp = seed2 << 8;
    288. seed3_tmp = seed3;
    289. seed = seed0_tmp + seed1_tmp + seed2_tmp + seed3_tmp;
    290. printf("seed is 0x%08x\n",seed);
    291. key = seed;//汽车厂自定义安全解锁的算法,这里直接key=seed。
    292. printf("key is 0x%08x\n",key);
    293. send[0].Data[0] = 0x06;
    294. send[0].Data[1] = 0x27;
    295. send[0].Data[2] = 0x02;
    296. send[0].Data[3] = (key & 0xff000000) >> 3*8;
    297. send[0].Data[4] = (key & 0x00ff0000) >> 2*8;
    298. send[0].Data[5] = (key & 0x0000ff00) >> 8;
    299. send[0].Data[6] = (key & 0x000000ff);
    300. }
    301. else if(2 == Seedsize)
    302. {
    303. seed0_tmp = seed0 << 1*8;
    304. seed1_tmp = seed1;
    305. seed = seed0_tmp + seed1_tmp;
    306. printf("seed is 0x%04x\n",seed);
    307. key_tmp = seed;//汽车厂自定义安全解锁的算法,这里直接key=seed。
    308. key = key_tmp & 0xffff;
    309. printf("key is 0x%04x\n",key );
    310. send[0].Data[0] = 0x04;
    311. send[0].Data[1] = 0x27;
    312. send[0].Data[2] = 0x02;
    313. send[0].Data[3] = (key & 0xff00) >> 1*8;
    314. send[0].Data[4] = (key & 0x00ff);
    315. }
    316. else
    317. {
    318. printf("Seedsize error!");
    319. goto SHUTDOWN;
    320. }
    321. if(VCI_Transmit(VCI_USBCAN2, 0, 0, send, 1) == 1)
    322. {
    323. printf("STEP[0X%02x] send key SEND SUCCESS!Index:%04d CAN1 TX ID:0x%08X data:0x",STEP,count,send[0].ID);
    324. count++;
    325. for(i=0;i0].DataLen;i++)
    326. {
    327. printf(" %02X",send[0].Data[i]);
    328. }
    329. printf("\n");
    330. }
    331. else
    332. {
    333. printf("STEP[%02x] VCI_Transmit failed!\n",STEP);
    334. goto SHUTDOWN;
    335. }
    336. CURRENT_STEP =STEP;//全局变量CURRENT_STEP是为了记录当前所处步骤(接收线程和自测时的模拟ECU需要这个变量)
    337. STEP = 0x00;//tester的CAN消息发送成功后将STEP设置为0x00是为了防止重复发送,也方便计算等待时间,长时间等待不到响应则判定测试失败
    338. usleep(500000);//延时500ms
    339. break;
    340. //step0x08:enter codeConversation
    341. case 0x08:
    342. //需要发送的帧,结构体设置
    343. send[0].Data[0] = 0x02;
    344. send[0].Data[1] = 0x10;
    345. send[0].Data[2] = 0x02;
    346. if(VCI_Transmit(VCI_USBCAN2, 0, 0, send, 1) == 1)
    347. {
    348. printf("STEP[0X%02x] enter codeConversationng SEND SUCCESS!Index:%04d CAN1 TX ID:0x%08X data:0x",STEP,count,send[0].ID);
    349. count++;
    350. for(i=0;i0].DataLen;i++)
    351. {
    352. printf(" %02X",send[0].Data[i]);
    353. }
    354. printf("\n");
    355. }
    356. else
    357. {
    358. printf("STEP[%02x] VCI_Transmit failed!",STEP);
    359. goto SHUTDOWN;
    360. }
    361. CURRENT_STEP =STEP;//全局变量CURRENT_STEP是为了记录当前所处步骤(接收线程和自测时的模拟ECU需要这个变量)
    362. STEP = 0x00;//tester的CAN消息发送成功后将STEP设置为0x00是为了防止重复发送,也方便计算等待时间,长时间等待不到响应则判定测试失败
    363. usleep(500000);//延时500ms
    364. break;
    365. //step0x09:ask seed
    366. case 0x09:
    367. //需要发送的帧,结构体设置
    368. send[0].Data[0] = 0x02;
    369. send[0].Data[1] = 0x27;
    370. send[0].Data[2] = 0x01;
    371. if(VCI_Transmit(VCI_USBCAN2, 0, 0, send, 1) == 1)
    372. {
    373. printf("STEP[0X%02x] ask seed SEND SUCCESS!Index:%04d CAN1 TX ID:0x%08X data:0x",STEP,count,send[0].ID);
    374. count++;
    375. for(i=0;i0].DataLen;i++)
    376. {
    377. printf(" %02X",send[0].Data[i]);
    378. }
    379. printf("\n");
    380. }
    381. else
    382. {
    383. printf("STEP[%02x] VCI_Transmit failed!",STEP);
    384. goto SHUTDOWN;
    385. }
    386. CURRENT_STEP =STEP;//全局变量CURRENT_STEP是为了记录当前所处步骤(接收线程和自测时的模拟ECU需要这个变量)
    387. STEP = 0x00;//tester的CAN消息发送成功后将STEP设置为0x00是为了防止重复发送,也方便计算等待时间,长时间等待不到响应则判定测试失败
    388. usleep(500000);//延时500ms
    389. break;
    390. //step0x91:send key
    391. case 0x91:
    392. //需要发送的帧,结构体设置
    393. //Seedsize有2和4两种可能,分别采取不同的组装CAN报文的形式
    394. if(4 == Seedsize)
    395. {
    396. seed0_tmp = seed0 << 3*8;
    397. seed1_tmp = seed1 << 2*8;
    398. seed2_tmp = seed2 << 8;
    399. seed3_tmp = seed3;
    400. seed = seed0_tmp + seed1_tmp + seed2_tmp + seed3_tmp;
    401. printf("seed is 0x%08x\n",seed);
    402. key = seed;//汽车厂自定义安全解锁的算法,这里直接key=seed。
    403. printf("key is 0x%08x\n",key);
    404. send[0].Data[0] = 0x06;
    405. send[0].Data[1] = 0x27;
    406. send[0].Data[2] = 0x02;
    407. send[0].Data[3] = (key & 0xff000000) >> 3*8;
    408. send[0].Data[4] = (key & 0x00ff0000) >> 2*8;
    409. send[0].Data[5] = (key & 0x0000ff00) >> 8;
    410. send[0].Data[6] = (key & 0x000000ff);
    411. }
    412. else if(2 == Seedsize)
    413. {
    414. seed0_tmp = seed0 << 1*8;
    415. seed1_tmp = seed1;
    416. seed = seed0_tmp + seed1_tmp;
    417. printf("seed is 0x%04x\n",seed);
    418. key_tmp = seed;//汽车厂自定义安全解锁的算法,这里直接key=seed。
    419. key = key_tmp & 0xffff;
    420. printf("key is 0x%04x\n",key );
    421. send[0].Data[0] = 0x04;
    422. send[0].Data[1] = 0x27;
    423. send[0].Data[2] = 0x02;
    424. send[0].Data[3] = (key & 0xff00) >> 1*8;
    425. send[0].Data[4] = (key & 0x00ff);
    426. }
    427. else
    428. {
    429. printf("Seedsize error!");
    430. goto SHUTDOWN;
    431. }
    432. if(VCI_Transmit(VCI_USBCAN2, 0, 0, send, 1) == 1)
    433. {
    434. printf("STEP[0X%02x] send key SEND SUCCESS!Index:%04d CAN1 TX ID:0x%08X data:0x",STEP,count,send[0].ID);
    435. count++;
    436. for(i=0;i0].DataLen;i++)
    437. {
    438. printf(" %02X",send[0].Data[i]);
    439. }
    440. printf("\n");
    441. }
    442. else
    443. {
    444. printf("STEP[%02x] VCI_Transmit failed!\n",STEP);
    445. goto SHUTDOWN;
    446. }
    447. CURRENT_STEP =STEP;//全局变量CURRENT_STEP是为了记录当前所处步骤(接收线程和自测时的模拟ECU需要这个变量)
    448. STEP = 0x00;//tester的CAN消息发送成功后将STEP设置为0x00是为了防止重复发送,也方便计算等待时间,长时间等待不到响应则判定测试失败
    449. usleep(500000);//延时500ms
    450. break;
    451. case 0x00:
    452. //还没有收到ECU回复
    453. printf("[WAITING RESPONSE]VCI_Receive have not found corresponding ECU response!\n");
    454. if(NoResCount < NO_RES_COUNT_MAX)
    455. {
    456. NoResCount++;
    457. }
    458. else
    459. {
    460. printf("VCI_Receive have not found corresponding ECU response > %d times,test failed!!!",NO_RES_COUNT_MAX);
    461. goto SHUTDOWN;
    462. }
    463. usleep(1000000);//延时1000ms
    464. break;
    465. //step0xFF:所有流程结束
    466. case 0xFF:
    467. //所有流程结束
    468. printf("VCI_Receive have found all corresponding ECU response!\n test SUCESS!!!\n");
    469. goto SHUTDOWN;
    470. break;
    471. default:
    472. printf("unknown step\n");
    473. goto SHUTDOWN;
    474. }
    475. // 自测模式下,以下代码用于CAN2通道模仿ECU给tester回复
    476. if(TESTMODE)
    477. {
    478. switch(CURRENT_STEP)//根据当前所处步骤决定ECU模拟器回复什么消息,本switch-case里所有的发送都是通过CAN2通道
    479. {
    480. case 0x01:
    481. //需要发送的帧,结构体设置
    482. send[0].ID= Ecu_DialogId +8; //ECU的响应报文的CANID时ECU_DialogId加8
    483. send[0].SendType=0;
    484. send[0].RemoteFlag=0;
    485. send[0].ExternFlag=0;
    486. send[0].DataLen=8;
    487. send[0].Data[0] = 0x06;
    488. send[0].Data[1] = 0x50;
    489. send[0].Data[2] = 0x03;
    490. send[0].Data[3] = 0x00;
    491. send[0].Data[4] = 0x32;
    492. send[0].Data[5] = 0x01;
    493. send[0].Data[6] = 0xf4;
    494. send[0].Data[7] = 0xaa;
    495. if(VCI_Transmit(VCI_USBCAN2, 0, 1, send, 1) == 1)
    496. {
    497. }
    498. else
    499. {
    500. printf("STEP[%02x] VCI_Transmit failed!",STEP);
    501. goto SHUTDOWN;
    502. }
    503. usleep(300000);//延时300ms
    504. break;
    505. case 0x07:
    506. //需要发送的帧,结构体设置
    507. send[0].ID= Ecu_DialogId + 8;
    508. send[0].SendType=0;
    509. send[0].RemoteFlag=0;
    510. send[0].ExternFlag=0;
    511. send[0].DataLen=8;
    512. if(0)//设为1,表示seedsize 4, 0表示seedsize2
    513. {
    514. send[0].Data[0] = 0x06;
    515. send[0].Data[1] = 0x67;
    516. send[0].Data[2] = 0x01;
    517. send[0].Data[3] = 0x88;
    518. send[0].Data[4] = 0x88;
    519. send[0].Data[5] = 0x88;
    520. send[0].Data[6] = 0x88;
    521. send[0].Data[7] = 0xaa;
    522. }
    523. else
    524. {
    525. send[0].Data[0] = 0x04;
    526. send[0].Data[1] = 0x67;
    527. send[0].Data[2] = 0x01;
    528. send[0].Data[3] = 0x88;
    529. send[0].Data[4] = 0x88;
    530. send[0].Data[5] = 0xaa;
    531. send[0].Data[6] = 0xaa;
    532. send[0].Data[7] = 0xaa;
    533. }
    534. if(VCI_Transmit(VCI_USBCAN2, 0, 1, send, 1) == 1)
    535. {
    536. }
    537. else
    538. {
    539. printf("STEP[%02x] VCI_Transmit failed!",STEP);
    540. goto SHUTDOWN;
    541. }
    542. usleep(300000);//延时300ms
    543. break;
    544. case 0x71:
    545. //需要发送的帧,结构体设置
    546. send[0].ID= Ecu_DialogId + 8;
    547. send[0].SendType=0;
    548. send[0].RemoteFlag=0;
    549. send[0].ExternFlag=0;
    550. send[0].DataLen=8;
    551. send[0].Data[0] = 0x02;
    552. send[0].Data[1] = 0x67;
    553. send[0].Data[2] = 0x02;
    554. send[0].Data[3] = 0xaa;
    555. send[0].Data[4] = 0xaa;
    556. send[0].Data[5] = 0xaa;
    557. send[0].Data[6] = 0xaa;
    558. send[0].Data[7] = 0xaa;
    559. if(VCI_Transmit(VCI_USBCAN2, 0, 1, send, 1) == 1)
    560. {
    561. }
    562. else
    563. {
    564. printf("STEP[%02x] VCI_Transmit failed!",STEP);
    565. goto SHUTDOWN;
    566. }
    567. usleep(300000);//延时300ms
    568. break;
    569. case 0x08:
    570. //需要发送的帧,结构体设置
    571. send[0].ID= Ecu_DialogId + 8;
    572. send[0].SendType=0;
    573. send[0].RemoteFlag=0;
    574. send[0].ExternFlag=0;
    575. send[0].DataLen=8;
    576. send[0].Data[0] = 0x06;
    577. send[0].Data[1] = 0x50;
    578. send[0].Data[2] = 0x02;
    579. send[0].Data[3] = 0x00;
    580. send[0].Data[4] = 0x32;
    581. send[0].Data[5] = 0x01;
    582. send[0].Data[6] = 0xf4;
    583. send[0].Data[7] = 0x00;
    584. if(VCI_Transmit(VCI_USBCAN2, 0, 1, send, 1) == 1)
    585. {
    586. }
    587. else
    588. {
    589. printf("STEP[%02x] VCI_Transmit failed!",STEP);
    590. goto SHUTDOWN;
    591. }
    592. usleep(300000);//延时300ms
    593. break;
    594. case 0x09:
    595. //需要发送的帧,结构体设置
    596. send[0].ID= Ecu_DialogId + 8;
    597. send[0].SendType=0;
    598. send[0].RemoteFlag=0;
    599. send[0].ExternFlag=0;
    600. send[0].DataLen=8;
    601. if(1)//设为1,表示seedsize 4, 0表示seedsize2
    602. {
    603. send[0].Data[0] = 0x06;
    604. send[0].Data[1] = 0x67;
    605. send[0].Data[2] = 0x01;
    606. send[0].Data[3] = 0x88;
    607. send[0].Data[4] = 0x88;
    608. send[0].Data[5] = 0x88;
    609. send[0].Data[6] = 0x88;
    610. send[0].Data[7] = 0xaa;
    611. }
    612. else
    613. {
    614. send[0].Data[0] = 0x04;
    615. send[0].Data[1] = 0x67;
    616. send[0].Data[2] = 0x01;
    617. send[0].Data[3] = 0x88;
    618. send[0].Data[4] = 0x88;
    619. send[0].Data[5] = 0xaa;
    620. send[0].Data[6] = 0xaa;
    621. send[0].Data[7] = 0xaa;
    622. }
    623. if(VCI_Transmit(VCI_USBCAN2, 0, 1, send, 1) == 1)
    624. {
    625. }
    626. else
    627. {
    628. printf("STEP[%02x] VCI_Transmit failed!",STEP);
    629. goto SHUTDOWN;
    630. }
    631. usleep(300000);//延时300ms
    632. break;
    633. //step0x91:send key
    634. case 0x91:
    635. //需要发送的帧,结构体设置
    636. send[0].ID= Ecu_DialogId + 8;
    637. send[0].SendType=0;
    638. send[0].RemoteFlag=0;
    639. send[0].ExternFlag=0;
    640. send[0].DataLen=8;
    641. send[0].Data[0] = 0x02;
    642. send[0].Data[1] = 0x67;
    643. send[0].Data[2] = 0x02;
    644. send[0].Data[3] = 0xaa;
    645. send[0].Data[4] = 0xaa;
    646. send[0].Data[5] = 0xaa;
    647. send[0].Data[6] = 0xaa;
    648. send[0].Data[7] = 0xaa;
    649. if(VCI_Transmit(VCI_USBCAN2, 0, 1, send, 1) == 1)
    650. {
    651. }
    652. else
    653. {
    654. printf("STEP[%02x] VCI_Transmit failed!",STEP);
    655. goto SHUTDOWN;
    656. }
    657. usleep(300000);//延时300ms
    658. break;
    659. default:
    660. printf("unknown CAN2 step:%02X\n",CURRENT_STEP);
    661. goto SHUTDOWN;
    662. }
    663. }
    664. }// while end
    665. SHUTDOWN:
    666. m_run0=0;//线程关闭指令。
    667. pthread_join(threadid,NULL);//等待线程关闭。
    668. usleep(100000);//延时100ms。
    669. //VCI_ResetCAN(VCI_USBCAN2, 0, 0);//复位CAN1通道。
    670. usleep(100000);//延时100ms。
    671. //VCI_CloseDevice(VCI_USBCAN2,0);//关闭设备。
    672. //除收发函数外,其它的函数调用前后,最好加个毫秒级的延时,即不影响程序的运行,又可以让USBCAN设备有充分的时间处理指令。
    673. //goto ext;
    674. }

    代码执行结果:

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

    3. 总结

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

  • 相关阅读:
    Ukey连接虚拟前置机,浦银安盛基金用USB Server解决
    论文阅读03(基于人类偏好微调语言模型)
    GTK构件之杂项构件(2)
    什么数据需要存在Redis里?缓存的缺点?怎样进行数据同步?
    Redis三种模式——主从复制,哨兵模式,集群
    1532_AURIX_TriCore内核架构_中断
    diffusers-Tasks
    数字政府一网统管体系下的运维管理软件应用探讨
    树莓派忘记密码重置密码的方法
    1995-2020年全国各省二氧化碳排放量面板数据
  • 原文地址:https://blog.csdn.net/qq_33163046/article/details/126762042