-
Notifications
You must be signed in to change notification settings - Fork 0
/
CANalystHelper.cs
865 lines (727 loc) · 40.5 KB
/
CANalystHelper.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
/*
* @Author:Intron
* @Data:2021.05.15
* @Edition:V0.9.0
* @Describe:
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
public struct VCI_BOARD_INFO
{
public UInt16 hw_Version; //硬件版本号,用16进制表示。比如0x0100表示V1.00。
public UInt16 fw_Version; //固件版本号,用16进制表示。比如0x0100表示V1.00。
public UInt16 dr_Version; //驱动程序版本号,用16进制表示。比如0x0100表示V1.00。
public UInt16 in_Version; //接口库版本号,用16进制表示。比如0x0100表示V1.00。
public UInt16 irq_Num; //保留参数。
public byte can_Num; //表示有几路CAN通道。
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] str_Serial_Num; //此板卡的序列号。
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
public byte[] str_hw_Type; //硬件类型,比如“USBCAN V1.00”(注意:包括字符串结束符’\0’)
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] Reserved; //系统保留。
}
/////////////////////////////////////////////////////
//2.定义CAN信息帧的数据类型。
unsafe public struct VCI_CAN_OBJ //使用不安全代码
{
public uint ID; //帧ID。32位变量,数据格式为靠右对齐。
public uint TimeStamp; //时间标识。设备接收到某一帧的时间标识。时间标示从CAN卡上电开始计时,计时单位为0.1ms。
public byte TimeFlag; //是否使用时间标识,为1时TimeStamp有效,TimeFlag和TimeStamp只在此帧为接收帧时有意义。
public byte SendType; //发送标志。=0时为正常发送(发送失败会自动重发,重发时间为4秒,4秒内没有发出则取消);=1时为单次发送(只发送一次,发送失败不会自动重发,总线只产生一帧数据);
public byte RemoteFlag; //是否是远程帧。=0时为为数据帧,=1时为远程帧(数据段空)。
public byte ExternFlag; //是否是扩展帧。=0时为标准帧(11位ID),=1时为扩展帧(29位ID)。
public byte DataLen; //数据长度,DLC (<=8),即CAN帧Data有几个字节。约束了后面Data[8]中的有效字节。
public fixed byte Data[8]; //数据。由于CAN规定了最大是8个字节,所以这里预留了8个字节的空间,受DataLen约束。如DataLen定义为3,即Data[0]、Data[1]、Data[2]是有效的。
public fixed byte Reserved[3];//保留位
}
//3.定义初始化CAN的数据类型
public struct VCI_INIT_CONFIG
{
public UInt32 AccCode;//验收码。SJA1000的帧过滤验收码。对经过屏蔽码过滤为“有关位”进行匹配,全部匹配成功后,此帧可以被接收。否则不接收。详见VCI_InitCAN。
public UInt32 AccMask;//屏蔽码。SJA1000的帧过滤屏蔽码。对接收的CAN帧ID进行过滤,对应位为0的是“有关位”,对应位为1的是“无关位”。屏蔽码推荐设置为0xFFFFFFFF,即全部接收。
public UInt32 Reserved;//
public byte Filter; //0或1接收所有帧。2标准帧滤波,3是扩展帧滤波。
public byte Timing0; //波特率参数,具体配置,请查看下面的表格
public byte Timing1;
public byte Mode; //模式,0表示正常模式,1表示只听模式,2自测模式
/*
* 波特率 10 Kbps 20 Kbps 40 Kbps 50 Kbps 80 Kbps 100 Kbps
* BTR0 0x31 0x18 0x87 0x09 0x83 0x04
* BTR1 0x1C 0x1C 0xFF 0x1C 0xFF 0x1C
* 波特率 125 Kbps 200 Kbps 250 Kbps 400 Kbps 500 Kbps 666 Kbps
* BTR0 0x03 0x81 0x01 0x80 0x00 0x80
* BTR1 0x1C 0xFA 0x1C 0xFA 0x1C 0xB6
* 波特率 800 Kbps 1000 Kbps 33.33 Kbps 66.66 Kbps 83.33 Kbps
* BTR0 0x00 0x00 0x09 0x04 0x03
* BTR1 0x16 0x14 0x6F 0x6F 0x6F
*/
}
/*------------其他数据结构描述---------------------------------*/
//4.USB-CAN总线适配器板卡信息的数据类型1,该类型为VCI_FindUsbDevice函数的返回参数。
public struct VCI_BOARD_INFO1
{
public UInt16 hw_Version;//硬件版本号,用16进制表示。比如0x0100表示V1.00。
public UInt16 fw_Version;//固件版本号,用16进制表示。比如0x0100表示V1.00。
public UInt16 dr_Version;//驱动程序版本号,用16进制表示。比如0x0100表示V1.00。
public UInt16 in_Version;//接口库版本号,用16进制表示。比如0x0100表示V1.00。
public UInt16 irq_Num;//保留参数。
public byte can_Num;//表示有几路CAN通道。
public byte Reserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] str_Serial_Num;//此板卡的序列号。
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] str_hw_Type;//硬件类型,比如“USBCAN V1.00”(注意:包括字符串结束符’\0’)
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] str_Usb_Serial;//
}
/*------------数据结构描述完成---------------------------------*/
public struct CHGDESIPANDPORT
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public byte[] szpwd;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public byte[] szdesip;
public Int32 desport;
public void Init()
{
szpwd = new byte[10];
szdesip = new byte[20];
}
}
namespace CANNalyst //------------------>注意:这个命名空间最好修改一下<------------------------\\
{
class CANalystHelper
{
/*
* 接口库函数使用流程
*
*
+----------------+
| VCI_OpenDevice |
+----------------+
|
+-------v--------+
| VCI_InitCAN |
+----------------+
+------------------+ |
|VCI_GetReceiveNum +---------->+ +---------------+
+------------------+ | <-----------+VCI_ClearBuffer|
+------------------+ | +---------------+
| VCI_ReadBoardInfo+---------->+
+------------------+ |
|
+------------------------------------------------------------------+
| 运行主框架 | |
| +<-------------------+ |
| | | |
| +-------v--------+ | |
| | VCI_StartCAN | | |
| +----------------+ | |
| | +------------+ |
| | <-----------+VCI_ResetCAN| |
| | +------------+ |
| +--------------+ | |
| | VCI_Transmit |------------->+ +------------+ |
| +--------------+ | <-----------+ VCI_Recive | |
| v +------------+ |
| +---------------+ |
| |VCI_CloseDevice| |
| +---------------+ |
| |
+------------------------------------------------------------------+
*
*/
/*------------分析仪设备类型声明---------------------------------*/
public const int DEV_USBCAN = 3;
public const int DEV_USBCAN2 = 4;
/*------------函数声明描述---------------------------------*/
/// <summary>
/// 此函数用以打开设备。注意一个设备只能打开一次。
/// </summary>
/// <param name="DeviceType">设备类型。对应不同的产品型号</param>
/// <param name="DeviceInd">设备索引,比如当只有一个USB-CAN适配器时,索引号为0,这时再插入一个USB-CAN适配器那么后面插入的这个设备索引号就是1,以此类推。</param>
/// <param name="Reserved">保留参数,通常为0。</param>
/// <returns>返回值=1,表示操作成功;=0表示操作失败</returns>
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_OpenDevice(UInt32 DeviceType, UInt32 DeviceInd, UInt32 Reserved);
/// <summary>
/// 此函数用以关闭设备。
/// </summary>
/// <param name="DeviceType">设备类型。对应不同的产品型号</param>
/// <param name="DeviceInd">设备索引,比如当只有一个USB-CAN适配器时,索引号为0,这时再插入一个USB-CAN适配器那么后面插入的这个设备索引号就是1,以此类推。对应已经打开的设备。</param>
/// <returns>返回值=1,表示操作成功;=0表示操作失败</returns>
[DllImport("controlcan.dll")]
/// <returns>返回值=1,表示操作成功;=0表示操作失败</returns>
public static extern UInt32 VCI_CloseDevice(UInt32 DeviceType, UInt32 DeviceInd);
/// <summary>
/// 此函数用以初始化指定的CAN通道。有多个CAN通道时,需要多次调用。
/// </summary>
/// <param name="DeviceType">设备类型。对应不同的产品型号</param>
/// <param name="DeviceInd">设备索引,比如当只有一个USB-CAN适配器时,索引号为0,这时再插入一个USB-CAN适配器那么后面插入的这个设备索引号就是1,以此类推。</param>
/// <param name="CANInd">CAN通道索引。第几路CAN。即对应卡的CAN通道号,CAN1为0,CAN2为1。</param>
/// <param name="pInitConfig">初始化参数结构。</param>
/// <returns></returns>
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_InitCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_INIT_CONFIG pInitConfig);
/// <summary>
/// 此函数用以获取设备信息。
/// </summary>
/// <param name="DeviceType">设备类型。对应不同的产品型号</param>
/// <param name="DeviceInd">设备索引,比如当只有一个USB-CAN适配器时,索引号为0,这时再插入一个USB-CAN适配器那么后面插入的这个设备索引号就是1,以此类推。</param>
/// <param name="pInfo">用来存储设备信息的VCI_BOARD_INFO结构指针。</param>
/// <returns>返回值=1,表示操作成功;=0表示操作失败</returns>
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_ReadBoardInfo(UInt32 DeviceType, UInt32 DeviceInd, ref VCI_BOARD_INFO pInfo);
/// <summary>
/// 此函数用以获取指定CAN通道的接收缓冲区中,接收到但尚未被读取的帧数量。主要用途是配合VCI_Receive使用,即缓冲区有数据,再接收。实际应用中,用户可以忽略该函数,直接循环调用VCI_Receive,可以节约PC系统资源,提高程序效率。
/// </summary>
/// <param name="DeviceType">设备类型。对应不同的产品型号</param>
/// <param name="DeviceInd">设备索引,比如当只有一个USB-CAN适配器时,索引号为0,这时再插入一个USB-CAN适配器那么后面插入的这个设备索引号就是1,以此类推。</param>
/// <param name="CANInd">CAN通道索引。第几路CAN。即对应卡的CAN通道号,CAN1为0,CAN2为1。</param>
/// <returns>返回尚未被读取的帧数,=-1表示USB-CAN设备不存在或USB掉线。</returns>
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_GetReceiveNum(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
/// <summary>
/// 此函数用以清空指定CAN通道的缓冲区。主要用于需要清除接收缓冲区数据的情况,同时发送缓冲区数据也会一并清除。
/// </summary>
/// <param name="DeviceType">设备类型。对应不同的产品型号</param>
/// <param name="DeviceInd">设备索引,比如当只有一个USB-CAN适配器时,索引号为0,这时再插入一个USB-CAN适配器那么后面插入的这个设备索引号就是1,以此类推。</param>
/// <param name="CANInd">CAN通道索引。第几路CAN。即对应卡的CAN通道号,CAN1为0,CAN2为1。</param>
/// <returns>返回值=1,表示操作成功;=0表示操作失败</returns>
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_ClearBuffer(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
/// <summary>
/// 此函数用以启动CAN卡的某一个CAN通道。有多个CAN通道时,需要多次调用。
/// </summary>
/// <param name="DeviceType">设备类型。对应不同的产品型号</param>
/// <param name="DeviceInd">设备索引,比如当只有一个USB-CAN适配器时,索引号为0,这时再插入一个USB-CAN适配器那么后面插入的这个设备索引号就是1,以此类推。</param>
/// <param name="CANInd">CAN通道索引。第几路CAN。即对应卡的CAN通道号,CAN1为0,CAN2为1。</param>
/// <returns>返回值=1,表示操作成功;=0表示操作失败</returns>
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_StartCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
/// <summary>
/// 此函数用以复位 CAN。主要用与 VCI_StartCAN配合使用,无需再初始化,即可恢复CAN卡的正常状态。比如当CAN卡进入总线关闭状态时,可以调用这个函数。
/// </summary>
/// <param name="DeviceType">设备类型。对应不同的产品型号</param>
/// <param name="DeviceInd">设备索引,比如当只有一个USB-CAN适配器时,索引号为0,这时再插入一个USB-CAN适配器那么后面插入的这个设备索引号就是1,以此类推。</param>
/// <param name="CANInd">CAN通道索引。第几路CAN。即对应卡的CAN通道号,CAN1为0,CAN2为1。</param>
/// <returns>返回值=1,表示操作成功;=0表示操作失败</returns>
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_ResetCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
/// <summary>
/// 发送函数。返回值为实际发送成功的帧数。
/// </summary>
/// <param name="DeviceType">设备类型。对应不同的产品型号</param>
/// <param name="DeviceInd">设备索引,比如当只有一个USB-CAN适配器时,索引号为0,这时再插入一个USB-CAN适配器那么后面插入的这个设备索引号就是1,以此类推。</param>
/// <param name="CANInd">CAN通道索引。第几路CAN。即对应卡的CAN通道号,CAN1为0,CAN2为1。</param>
/// <param name="pSend">要发送的帧结构体 VCI_CAN_OBJ数组的首指针。</param>
/// <param name="Len">要发送的帧结构体数组的长度(发送的帧数量)。最大为1000,建议设为1,每次发送单帧,以提高发送效率。</param>
/// <returns>返回实际发送的帧数,=-1表示USB-CAN设备不存在或USB掉线。</returns>
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_Transmit(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pSend, UInt32 Len);
/// <summary>
/// 接收函数。此函数从指定的设备CAN通道的接收缓冲区中读取数据。
/// </summary>
/// <param name="DeviceType">设备类型。对应不同的产品型号</param>
/// <param name="DeviceInd">设备索引,比如当只有一个USB-CAN适配器时,索引号为0,这时再插入一个USB-CAN适配器那么后面插入的这个设备索引号就是1,以此类推。</param>
/// <param name="CANInd">CAN通道索引。第几路CAN。即对应卡的CAN通道号,CAN1为0,CAN2为1。</param>
/// <param name="pReceive">用来接收的帧结构体VCI_CAN_OBJ数组的首指针。注意:数组的大小一定要比下面的len参数大,否则会出现内存读写错误。</param>
/// <param name="Len">用来接收的帧结构体数组的长度(本次接收的最大帧数,实际返回值小于等于这个值)。该值为所提供的存储空间大小,适配器中为每个通道设置了2000帧左右的接收缓存区,用户根据自身系统和工作环境需求,在1到2000之间选取适当的接收数组长度。</param>
/// <param name="WaitTime">保留参数。</param>
/// <returns></returns>
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_Receive(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pReceive, UInt32 Len, Int32 WaitTime);
/*------------其他函数描述---------------------------------*/
/// <summary>
///
/// </summary>
/// <param name="DevType"></param>
/// <param name="DevIndex"></param>
/// <returns></returns>
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_ConnectDevice(UInt32 DevType, UInt32 DevIndex);
/// <summary>
/// 复位USB-CAN适配器,复位后需要重新使用VCI_OpenDevice打开设备。等同于插拔一次USB设备。
/// </summary>
/// <param name="DevType">设备类型。对应不同的产品型号</param>
/// <param name="DevIndex">设备索引,比如当只有一个USB-CAN适配器时,索引号为0,当有多个时,索引号从0开始依次递增。</param>
/// <param name="Reserved">保留。</param>
/// <returns>返回值=1,表示操作成功;=0表示操作失败</returns>
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_UsbDeviceReset(UInt32 DevType, UInt32 DevIndex, UInt32 Reserved);
/// <summary>
/// 当同一台PC上使用多个USB-CAN的时候,可用此函数查找当前的设备,并获取所有设备的序列号。最多支持50个设备。
/// </summary>
/// <param name="pInfo">结构体数组首地址,用来存储设备序列号等信息的结构体数组。数组长度建议定义为50,如:VCI_BOARD_INFO pInfo[50]。</param>
/// <returns>返回计算机中已插入的USB-CAN适配器的数量。</returns>
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_FindUsbDevice(ref VCI_BOARD_INFO1 pInfo);
/*------------函数描述结束---------------------------------*/
/*------------默认CAN分析仪参数配置---------------------------------*/
public static UInt32 m_devtype = DEV_USBCAN2;//USBCAN2
public UInt32 m_bOpen = 0;
public UInt32 m_devind = 0;//设备索引号0;比如当只有一个USB-CAN适配器时,索引号为0,这时再插入一个USB-CAN适配器那么后面插入的这个设备索引号就是1,以此类推。
public UInt32 m_canind = 0;//CAN通道索引。第几路CAN。即对应卡的CAN通道号,CAN1为0,CAN2为1。
VCI_CAN_OBJ[] m_recobj = new VCI_CAN_OBJ[1000];
UInt32[] m_arrdevtype = new UInt32[20];
public string AccCode = "00000000";//验收码
public string AccMask = "FFFFFFFF";//屏蔽码
public string Timing0 = "00";
public string Timing1 = "1C";
public Byte CANFilter = 1;//滤波方式:1--接受全部;2--只接收标准帧;3--只接收扩展帧;
public Byte CANMode = 0;//接收模式:0--正常;1--只收;2--回环;
System.Timers.Timer RevTimer = new System.Timers.Timer(2000);
static bool IsAdditionalClear = true;//额外清除buffer开关
/*------------默认CAN分析仪参数配置结束---------------------------------*/
/*
* 错误代码:
* 0x00---00---000
* 前两位:错误过程
* 中间两位:错误结果
* 最后三位:错误位置
*
*/
/// <summary>
/// 类初始化
/// </summary>
public CANalystHelper()
{
RevTimer.Elapsed += new System.Timers.ElapsedEventHandler(Rev2Timer);
}
public void GetBordInfo()
{
VCI_BOARD_INFO info = new VCI_BOARD_INFO();
VCI_ReadBoardInfo(m_devtype, m_devind,ref info);
Console.WriteLine(info);
}
/// <summary>
/// 配置CAN分析仪参数
/// </summary>
/// <param name="Acccode">验收码</param>
/// <param name="Accmask">屏蔽码</param>
/// <param name="T0">时间参数1</param>
/// <param name="T1">时间参数2</param>
/// <param name="Fliter">滤波方式:1--接受全部;2--只接收标准帧;3--只接收扩展帧</param>
/// <param name="Mode">接收模式:0--正常;1--只收;2--回环</param>
/// <param name="DevID">设备索引号0;比如当只有一个USB-CAN适配器时,索引号为0,这时再插入一个USB-CAN适配器那么后面插入的这个设备索引号就是1,以此类推。</param>
/// <param name="CANID">CAN通道索引。第几路CAN。即对应卡的CAN通道号,CAN1为0,CAN2为1。</param>
public void SetCANDeviceConfig(string Acccode = "00000000", string Accmask = "FFFFFFFF", string T0 = "00", string T1 = "1C", Byte Fliter = 1, Byte Mode = 0,UInt32 DevID = 0,UInt32 CANID = 0)
{
AccCode = Acccode;
AccMask = Accmask;
Timing0 = T0;
Timing1 = T1;
CANFilter = Fliter;
CANMode = Mode;
m_devind = DevID;
m_canind = CANID;
}
/// <summary>
/// 此函数用以打开设备。注意一个设备只能打开一次。
/// </summary>
/// <param name="IsMesgBox">当发生错误时,是否弹窗进行提示</param>
/// <returns>返回值=true,表示操作成功;=false表示操作失败;</returns>
public bool Strat(bool IsMesgBox = false)
{
if (VCI_OpenDevice(m_devtype, m_devind, 0) == 0)
{
if(IsMesgBox) MessageBox.Show("打开设备失败,请检查设备类型和设备索引号是否正确", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
RevTimer.Stop();
return false;
}
VCI_INIT_CONFIG config = new VCI_INIT_CONFIG();
config.AccCode = System.Convert.ToUInt32("0x" + AccCode, 16);
config.AccMask = System.Convert.ToUInt32("0x" + AccMask, 16);
config.Timing0 = System.Convert.ToByte("0x" + Timing0, 16);
config.Timing1 = System.Convert.ToByte("0x" + Timing1, 16);
config.Filter = CANFilter;
config.Mode = CANMode;
if(VCI_InitCAN(m_devtype, m_devind, m_canind, ref config)==0)
{
if (IsMesgBox) MessageBox.Show("初始化设备失败,USB-CAN设备不存在或USB掉线,请检查设备类型和设备索引号是否正确", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
RevTimer.Stop();
return false;
}
if (VCI_StartCAN(m_devtype, m_devind, m_canind)==0)
{
if (IsMesgBox) MessageBox.Show("启动设备失败,USB-CAN设备不存在或USB掉线,请检查设备类型和设备索引号是否正确", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
RevTimer.Stop();
return false;
}
RevTimer.Start();
return true;
}
/// <summary>
/// 此函数用以关闭设备。
/// </summary>
/// <param name="IsMesgBox">当发生错误时,是否弹窗进行提示</param>
/// <returns>返回值=true,表示操作成功;=false表示操作失败;</returns>
public bool Close(bool IsMesgBox = false)
{
if (VCI_CloseDevice(m_devtype, m_devind) == 0)
{
if (IsMesgBox) MessageBox.Show("关闭设备失败,USB-CAN设备不存在或USB掉线,请检查设备类型和设备索引号是否正确", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return false;
}
RevTimer.Stop();
return true;
}
/// <summary>
/// 此函数用以清空指定CAN通道的缓冲区。主要用于需要清除接收缓冲区数据的情况,同时发送缓冲区数据也会一并清除。
/// </summary>
/// <param name="id">CAN通道索引。第几路CAN。即对应卡的CAN通道号,CAN1为0,CAN2为1。</param>
/// <returns>返回值=true,表示操作成功;=false表示操作失败;</returns>
public bool ClearBuffer(UInt32 id= 0, bool IsMesgBox = false)
{
if (VCI_ClearBuffer(m_devtype, m_devind, id) == 0)
{
if (IsMesgBox) MessageBox.Show("清楚缓冲区失败,USB-CAN设备不存在或USB掉线,请检查设备类型和设备索引号是否正确", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return false;
}
return true;
}
/// <summary>
/// 发送一条CAN消息
/// </summary>
/// <param name="id">CAN ID,格式为"00000000"由八位组成</param>
/// <param name="Msg">要发送的消息,格式为"00000000"由八位组成</param>
/// <param name="IsMesgBox">当发生错误时,是否弹窗进行提示</param>
/// <returns>返回值=true,表示操作成功;=false表示操作失败;</returns>
unsafe public bool SendOneMsg(string id, string Msg, bool IsMesgBox = false)
{
VCI_CAN_OBJ sendobj = new VCI_CAN_OBJ();
sendobj.RemoteFlag = (byte)0;
sendobj.ExternFlag = (byte)0;
sendobj.ID = System.Convert.ToUInt32("0x" + id, 16);
int len = (Msg.Length + 1) / 3;
sendobj.DataLen = System.Convert.ToByte(len);
String strdata = Msg;
int i = -1;
try
{
if (i++ < len - 1)
sendobj.Data[0] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[1] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[2] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[3] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[4] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[5] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[6] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[7] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
if (VCI_Transmit(m_devtype, m_devind, m_canind, ref sendobj, 1) == 0)
{
if (IsMesgBox) MessageBox.Show("发送失败", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return false;
}
else { Console.WriteLine("[OK]" + "\t" + sendobj.ID + "\t" + strdata); return true; }
}
/// <summary>
/// 调用此函数可以实现读取所有收到的消息。
/// </summary>
/// <returns></returns>
unsafe public Queue RevAllMsg()
{
UInt32 res = new UInt32();
Queue Rev = new Queue(2000);
res = VCI_Receive(m_devtype, m_devind, m_canind, ref m_recobj[0], 1000, 100);
if (res == 0xFFFFFFFF) res = 0;//当设备未初始化时,返回0xFFFFFFFF,不进行列表显示。
String str = "";
for (UInt32 i = 0; i < res; i++)
{
str = "接收到数据: ";
str += " 帧ID:0x" + System.Convert.ToString(m_recobj[i].ID, 16);
str += " 帧格式:";
if (m_recobj[i].RemoteFlag == 0)
str += "数据帧 ";
else
str += "远程帧 ";
if (m_recobj[i].ExternFlag == 0)
str += "标准帧 ";
else
str += "扩展帧 ";
//////////////////////////////////////////
if (m_recobj[i].RemoteFlag == 0)
{
str += "数据: ";
byte len = (byte)(m_recobj[i].DataLen % 9);
byte j = 0;
fixed (VCI_CAN_OBJ* m_recobj1 = &m_recobj[i])
{
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[0], 16);
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[1], 16);
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[2], 16);
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[3], 16);
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[4], 16);
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[5], 16);
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[6], 16);
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[7], 16);
}
}
Console.WriteLine(str);
Rev.Enqueue(str);
}
return Rev;
}
/// <summary>
/// 发送一个同步报文。每个节点都以该同步报文作为PDO触发参数,因此该同步报文的COB-ID 具有比较高的优先级以及最短的传输时间。
/// </summary>
/// <returns>返回值=1,表示操作成功;=0表示操作失败;</returns>
unsafe public bool SengSYNC()
{
return SendOneMsg("00000080", " ");
}
unsafe public bool SendRPDO(int id,string Msg)
{
string node = "000005";
if (id>9)
{
node = node + id.ToString();
}
else
{
node = node + "0" + id.ToString();
}
return SendOneMsg(node, Msg);
}
private void Rev2Timer(object sender, System.Timers.ElapsedEventArgs e)
{
if (IsAdditionalClear)
{
RevAllMsg();
}
}
}
class HDTDriver
{
/*------------CANOpen报文---------------------------------*/
/*
* 控制字命令
*/
public const string CTR_WORD_ENABLE = "2B 40 60 00 00 00 00 00";
public const string CTR_WORD_SWITCH_DISABLE = "2B 40 60 00 06 00 00 00";
public const string CTR_WORD_SWITCH_ON = "2B 40 60 00 07 00 00 00";
public const string CTR_WORD_ENABLE_OPERATION = "2B 40 60 00 0F 00 00 00";
public const string CTR_WORD_ENABLE_IP_OP = "2B 40 60 00 1F 00 00 00";
public const string CTR_WORD_DISENABLE_IP = "2B 40 60 00 0F 00 00 00";
public const string CTR_WORD_FAULT_RESET = "2B 40 60 00 40 00 00 00";
/*
* 电机运动模式
*/
public const string MODE_WORD_IP = "2F 60 60 00 07 00 00 00";
public const string MODE_WORD_VELOCITY = "2F 60 60 00 03 00 00 00";
public const string MODE_WORD_POSITION = "2F 60 60 00 01 00 00 00";
/*
* 插补运动模式配置
*/
public const string IP_MODE_RPDO_ENTRIES_CLEAR = "2F 03 16 00 00 00 00 00";
public const string IP_MODE_RPDO_Mapping = "23 03 16 01 20 01 C1 60";
public const string IP_MODE_RPDO_ENTRIES_SET = "2F 03 16 00 01 00 00 00";
public const string IP_MODE_RPDO_TRANSMISSION_TYPE = "2F 03 14 02 01 00 00 00";
//public const string IP_MODE_SUBMODE_CUBICSPINE_SET = "2F C0 60 00 FF 00 00 00";//-1 三次样条插补
public const string IP_MODE_SUBMODE_CUBICSPINE_SET = "2F C0 60 00 00 00 00 00";//0 直线样条插补
public const string IP_MODE_TIME_PERIOD_SET = "23 C2 60 01 32 00 00 00";//50ms
public const string IP_MODE_TIME_INDEX_SET = "23 C2 60 02 FD 00 00 00";//-3
/*
* 速度运动模式配置
*/
/*
* 位置运动模式配置
*/
public const string POS_MODE_ENABLE = "2B 40 60 00 0F 00 00 00";
public const string POS_MODE_CHANGE_IMMEDIATELY= "2B 40 60 00 1F 00 00 00";
private string ID = "00000602";
CANalystHelper CANalyst;
Thread SendMsg;
/// <summary>
/// 类初始化函数
/// </summary>
/// <param name="id">控制ID,基本结构为"00000601"</param>
/// <param name="CAN">CAN分析仪接口类</param>
public HDTDriver(string id, CANalystHelper CAN)
{
ID = id;
CANalyst = CAN;
}
/// <summary>
/// 配置驱动器ID
/// </summary>
/// <param name="id">CAN ID,格式为"00000601"</param>
public void SetHDTID(string id)
{
ID = id;
}
/// <summary>
/// 获取当前ID
/// </summary>
/// <returns></returns>
public string GetHDTID()
{
return ID;
}
/// <summary>
/// HDT驱动器的初始化操作
/// </summary>
/// <returns></returns>
public bool HDTInit()
{
CANalyst.SendOneMsg(ID, CTR_WORD_FAULT_RESET);
CANalyst.SendOneMsg(ID, CTR_WORD_SWITCH_DISABLE);
CANalyst.SendOneMsg(ID, CTR_WORD_SWITCH_ON);
CANalyst.SendOneMsg(ID, CTR_WORD_ENABLE_OPERATION);
CANalyst.SendOneMsg(ID, CTR_WORD_ENABLE_IP_OP);
CANalyst.SendOneMsg(ID, IP_MODE_RPDO_ENTRIES_CLEAR);
CANalyst.SendOneMsg(ID, IP_MODE_RPDO_ENTRIES_SET);
CANalyst.SendOneMsg(ID, IP_MODE_RPDO_TRANSMISSION_TYPE);
CANalyst.SendOneMsg(ID, MODE_WORD_IP);
return true;
}
/// <summary>
/// 发送同步报文
/// </summary>
public void SendSYNC()
{
CANalyst.SendOneMsg("00000080", " ");
}
/// <summary>
/// 插补模式初始化操作
/// </summary>
public void IPInit()
{
CANalyst.SendOneMsg(ID, CTR_WORD_FAULT_RESET);
CANalyst.SendOneMsg(ID, CTR_WORD_ENABLE);
CANalyst.SendOneMsg(ID, CTR_WORD_SWITCH_DISABLE);
CANalyst.SendOneMsg(ID, CTR_WORD_SWITCH_ON);
CANalyst.SendOneMsg(ID, CTR_WORD_ENABLE_OPERATION);
CANalyst.SendOneMsg(ID, CTR_WORD_ENABLE_IP_OP);
CANalyst.SendOneMsg(ID, IP_MODE_RPDO_ENTRIES_CLEAR);
CANalyst.SendOneMsg(ID, IP_MODE_RPDO_Mapping);
CANalyst.SendOneMsg(ID, IP_MODE_RPDO_ENTRIES_SET);
CANalyst.SendOneMsg(ID, IP_MODE_RPDO_TRANSMISSION_TYPE);
CANalyst.SendOneMsg(ID, MODE_WORD_IP);
CANalyst.SendOneMsg(ID, CTR_WORD_ENABLE_IP_OP);
CANalyst.SendOneMsg(ID, IP_MODE_SUBMODE_CUBICSPINE_SET);
CANalyst.SendOneMsg(ID, IP_MODE_TIME_PERIOD_SET);
CANalyst.SendOneMsg(ID, IP_MODE_TIME_INDEX_SET);
CANalyst.SendOneMsg(ID, CTR_WORD_ENABLE_IP_OP);
}
/// <summary>
/// 设置插补模式的位置,已包含同步报文
/// </summary>
/// <param name="Pos">要运动的位置</param>
public void SetIPosition(int Pos)
{
string str = Int2Hex(Pos);
CANalyst.SendOneMsg(ID, "23 C1 60 01 "+str);
SendSYNC();
}
/// <summary>
/// 停止插补运动
/// </summary>
public void IPStop()
{
CANalyst.SendOneMsg(ID, CTR_WORD_ENABLE_OPERATION);
}
/// <summary>
/// 速度模式初始化
/// </summary>
public void VelocityInit()
{
CANalyst.SendOneMsg(ID, CTR_WORD_FAULT_RESET);
CANalyst.SendOneMsg(ID, CTR_WORD_SWITCH_DISABLE);
CANalyst.SendOneMsg(ID, CTR_WORD_SWITCH_ON);
CANalyst.SendOneMsg(ID, CTR_WORD_ENABLE_OPERATION);
CANalyst.SendOneMsg(ID, MODE_WORD_VELOCITY);
SetVelocity(0);
}
/// <summary>
/// 设置速度模式的速度
/// </summary>
/// <param name="vel">速度</param>
public void SetVelocity(Int32 vel)
{
string str = Int2Hex(vel);
CANalyst.SendOneMsg(ID, "23 FF 60 00 "+ str);
}
/// <summary>
/// 位置模式初始化
/// </summary>
public void PositInit()
{
CANalyst.SendOneMsg(ID, CTR_WORD_FAULT_RESET);
CANalyst.SendOneMsg(ID, CTR_WORD_SWITCH_DISABLE);
CANalyst.SendOneMsg(ID, CTR_WORD_SWITCH_ON);
CANalyst.SendOneMsg(ID, CTR_WORD_ENABLE_OPERATION);
CANalyst.SendOneMsg(ID, MODE_WORD_POSITION);
}
/// <summary>
/// 设置位置模式的位置
/// </summary>
/// <param name="pos">位置</param>
public void SetPosition(Int32 pos)
{
string str = Int2Hex(pos);
CANalyst.SendOneMsg(ID, "23 7A 60 00 " + str);
CANalyst.SendOneMsg(ID, POS_MODE_ENABLE);
CANalyst.SendOneMsg(ID, POS_MODE_CHANGE_IMMEDIATELY);
}
public string Float2ByteStr(float num)
{
byte[] HexVal = BitConverter.GetBytes(num);
return ByteArrayToHexString(HexVal);
}
public static string ByteArrayToHexString(byte[] data)
{
StringBuilder sb = new StringBuilder(data.Length * 3);
foreach (byte b in data)
{
sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' '));
}
return sb.ToString().ToUpper().Trim(' ');
}
public string Int2Hex(int num)
{
string a = Convert.ToString(num, 16);
int b = 8 - a.Length;
for (int i = 0; i < b; i++)
{
a = "0" + a;
}
a = a.ToUpper();
//Console.WriteLine(a[6].ToString() + a[7].ToString() + " " + a[4].ToString() + a[5].ToString() + " " + a[2].ToString() + a[3].ToString() + " " + a[0].ToString() + a[1].ToString());
return a[6].ToString() + a[7].ToString() + " " + a[4].ToString() + a[5].ToString() + " " + a[2].ToString() + a[3].ToString() + " " + a[0].ToString() + a[1].ToString();
}
}
}