#ifndef CONTROLCAN_H
#define CONTROLCAN_H

////文件版本：v2.02 20190609


//接口卡类型定义, 设备类型。
#define VCI_USBCAN1		3
#define VCI_USBCAN2		4
#define VCI_USBCAN2A		4

#define VCI_USBCAN_E_U 		20
#define VCI_USBCAN_2E_U 	21

//函数调用返回状态值
#define	STATUS_OK					1
#define STATUS_ERR					0
	
#define USHORT unsigned short int
#define BYTE unsigned char
#define CHAR char
#define UCHAR unsigned char
#define UINT unsigned int
#define DWORD unsigned int
#define PVOID void*
#define ULONG unsigned int
#define INT int
#define UINT32 UINT
#define LPVOID void*
#define BOOL BYTE
#define TRUE 1
#define FALSE 0

//1.ZLGCAN系列接口卡信息的数据类型。
//VCI_BOARD_INFO结构体包含USB-CAN系列接口卡的设备信息。结构体将在VCI_ReadBoardInfo函数中被填充。
typedef  struct  _VCI_BOARD_INFO{
		USHORT	hw_Version;				//硬件版本号,用16进制表示。比如0x0100表示V1.00。
		USHORT	fw_Version;				//固件版本号,用16进制表示。比如0x0100表示V1.00。
		USHORT	dr_Version;				//驱动程序版本号,用16进制表示。比如0x0100表示V1.00。
		USHORT	in_Version;				//接口库版本号,用16进制表示。比如0x0100表示V1.00。
		USHORT	irq_Num;				//保留参数
		BYTE	can_Num;				//表示有几路CAN通道。
		CHAR	str_Serial_Num[20];		//此板卡的序列号。
		CHAR	str_hw_Type[40];		//硬件类型,比如“USBCAN V1.00”(注意:包括字符串结束符’\0’)
		USHORT	Reserved[4];			//系统保留。
} VCI_BOARD_INFO,*PVCI_BOARD_INFO; 

//2.定义CAN信息帧的数据类型。
//VCI_CAN_OBJ结构体是CAN帧结构体,即1个结构体表示一个帧的数据结构。在发送函数VCI_Transmit和接收函数VCI_Receive中,被用来传送CAN信息帧。
typedef  struct  _VCI_CAN_OBJ{
	UINT	ID;							//帧ID。32位变量,数据格式为靠右对齐。详情请参照:《8. 附件 1 : ID 对齐方式 .pdf》说明文档。
	UINT	TimeStamp;					//设备接收到某一帧的时间标识。时间标示从CAN卡上电开始计时,计时单位为0.1ms。
	BYTE	TimeFlag;					//是否使用时间标识,为1时TimeStamp有效,TimeFlag和TimeStamp只在此帧为接收帧时有意义。
	BYTE	SendType;					//发送帧类型。
											//	=0时为正常发送(发送失败会自动重发,重发时间为4秒,4秒内没有发出则取消);
											//	=1时为单次发送(只发送一次,发送失败不会自动重发,总线只产生一帧数据);
											//	其它值无效。
											//	(二次开发,建议SendType=1,提高发送的响应速度)
	BYTE	RemoteFlag;					//是否是远程帧。=0时为为数据帧,=1时为远程帧(数据段空)。
	BYTE	ExternFlag;					//是否是扩展帧。=0时为标准帧(11位ID),=1时为扩展帧(29位ID)。
	BYTE	DataLen;					//数据长度 DLC (<=8),即CAN帧Data有几个字节。约束了后面Data[8]中的有效字节。
	BYTE	Data[8];					//CAN帧的数据。由于CAN规定了最大是8个字节,所以这里预留了8个字节的空间,受
											//DataLen约束。如DataLen定义为3,即Data[0]、Data[1]、Data[2]是有效的。
	BYTE	Reserved[3];				//系统保留。
}VCI_CAN_OBJ,*PVCI_CAN_OBJ;

//3.定义初始化CAN的数据类型
//VCI_INIT_CONFIG结构体定义了初始化CAN的配置。结构体将在VCI_InitCan函数中被
//填充,即初始化之前,要先填好这个结构体变量。
typedef struct _INIT_CONFIG{
	DWORD	AccCode;	//验收码。SJA1000的帧过滤验收码。对经过屏蔽码过滤为“有关位”进行匹配,全部匹
							//配成功后,此帧可以被接收。否则不接收。详见VCI_InitCAN。
	DWORD	AccMask;	//屏蔽码。SJA1000的帧过滤屏蔽码。对接收的CAN帧ID进行过滤,对应位为0的是“有
							//关位”,对应位为1的是“无关位”。屏蔽码推荐设置为0xFFFFFFFF,即全部接收。
	DWORD	Reserved;	//保留。
	UCHAR	Filter;		//滤波方式,允许设置为0-3,详细请参照2.2.3节的滤波模式对照表。
	UCHAR	Timing0;	//波特率定时器 0(BTR0)。设置值见下表。
	UCHAR	Timing1;	//波特率定时器 1(BTR1)。设置值见下表。
	UCHAR	Mode;		//模式。 =0表示正常模式(相当于正常节点), =1表示只听模式(只接收,不影响总线),
							//=2表示自发自收模式(环回模式)。
}VCI_INIT_CONFIG,*PVCI_INIT_CONFIG;

///////// new add struct for filter /////////
typedef struct _VCI_FILTER_RECORD{
	DWORD ExtFrame;	//是否为扩展帧
	DWORD Start;
	DWORD End;
}VCI_FILTER_RECORD,*PVCI_FILTER_RECORD;

#ifdef __cplusplus
#define EXTERN_C  extern "C"
#else
#define EXTERN_C
#endif







//参数描述
//DWORD DeviceType				设备类型。(linux版默认为 VCI_USBCAN2 )
//DWORD DevType					设备类型。(linux版默认为 VCI_USBCAN2 )
//DWORD DeviceInd				设备索引, 默认为0
									// 	比如当只有一个USB-CAN适配器时,索引号为0,这时再插入一个USB-CAN适配器
									//那么后面插入的这个设备索引号就是1,以此类推。
//DWORD Reserved				保留参数,通常为 0。
//DWORD CANInd					CAN通道索引。第几路 CAN。即对应卡的CAN通道号,CAN1为0,CAN2为1。

//PVCI_INIT_CONFIG pInitConfig	初始化参数结构。
//PVCI_BOARD_INFO pInfo			用来存储设备信息的VCI_BOARD_INFO结构指针。

//return DWORD					返回值=1,表示操作成功; =0表示操作失败; =-1表示USB-CAN设备不存在或USB掉线。
//return ULONG					返回消息数据的帧数,=-1表示USB-CAN设备不存在或USB掉线。


//此函数用以打开设备。注意一个设备只能打开一次。
EXTERN_C DWORD VCI_OpenDevice(DWORD DeviceType,DWORD DeviceInd,DWORD Reserved);
//此函数用以关闭设备。注意一个设备只能关闭一次。
EXTERN_C DWORD VCI_CloseDevice(DWORD DeviceType,DWORD DeviceInd);
//此函数用以初始化指定的CAN通道。有多个CAN通道时,需要多次调用。
EXTERN_C DWORD VCI_InitCAN(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd, PVCI_INIT_CONFIG pInitConfig);
//此函数用以获取设备信息。
EXTERN_C DWORD VCI_ReadBoardInfo(DWORD DeviceType,DWORD DeviceInd,PVCI_BOARD_INFO pInfo);

EXTERN_C DWORD VCI_SetReference(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,DWORD RefType,PVOID pData);

//此函数用以获取指定CAN通道的接收缓冲区中,接收到但尚未被读取的帧数量。主要
//用途是配合VCI_Receive使用,即缓冲区有数据,再接收。
//实际应用中,用户可以忽略该函数,直接循环调用VCI_Receive,可以节约PC系统资源,提高程序效率。
// 返回尚未被读取的帧数,
EXTERN_C ULONG VCI_GetReceiveNum(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
//此函数用以清空指定CAN通道的缓冲区。主要用于需要清除接收缓冲区数据的情况,同时发送
//缓冲区数据也会一并清除。
EXTERN_C DWORD VCI_ClearBuffer(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);

//此函数用以启动CAN卡的某一个CAN通道。有多个CAN通道时,需要多次调用。
EXTERN_C DWORD VCI_StartCAN(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
//此函数用以复位 CAN。主要用与 VCI_StartCAN配合使用,无需再初始化,即可恢复CAN卡
//的正常状态。比如当CAN卡进入总线关闭状态时,可以调用这个函数。
EXTERN_C DWORD VCI_ResetCAN(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);

//发送函数。返回值为实际发送成功的帧数。
//PVCI_CAN_OBJ pSend	要发送的帧结构体 VCI_CAN_OBJ数组的首指针。
//UINT Len				要发送的帧结构体数组的长度(发送的帧数量)。最大为1000,建议设为1,每次发送
							//单帧,以提高发送效率。
//return ULONG			返回实际发送的帧数,=-1表示USB-CAN设备不存在或USB掉线。
EXTERN_C ULONG VCI_Transmit(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_OBJ pSend,UINT Len);

//接收函数。此函数从指定的设备CAN通道的接收缓冲区中读取数据。
//PVCI_CAN_OBJ pReceive	用来接收的帧结构体VCI_CAN_OBJ数组的首指针。注意:数组的大小一定要比下面的len
							//参数大,否则会出现内存读写错误。
//UINT Len				用来接收的帧结构体数组的长度(本次接收的最大帧数,实际返回值小于等于这个值)。
							//该值为所提供的存储空间大小,适配器中为每个通道设置了2000帧左右的接收缓存区,用户
							//根据自身系统和工作环境需求,在1到2000之间选取适当的接收数组长度。一般pReceive数
							//组大小与Len都设置大于2000,如:2500为宜,可有效防止数据溢出导致地址冲突。同时每
							//隔30ms调用一次VCI_Receive为宜。
							//(在满足应用的时效性情况下,尽量降低调用VCI_Receive
							//的频率,只要保证内部缓存不溢出,每次读取并处理更多帧,可以提高运行效率。)
//INT WaitTime			保留参数。
//return ULONG			返回实际读取的帧数,=-1表示USB-CAN设备不存在或USB掉线。
EXTERN_C ULONG VCI_Receive(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_OBJ pReceive,UINT Len,INT WaitTime);


//复位USB-CAN适配器,复位后需要重新使用VCI_OpenDevice打开设备。等同于插拔一次USB设备。
EXTERN_C DWORD  VCI_UsbDeviceReset(DWORD DevType,DWORD DevIndex,DWORD Reserved);
//当同一台PC上使用多个USB-CAN的时候,可用此函数查找当前的设备,并获取所有设备的序列号。最多支持50个设备。
//PVCI_BOARD_INFO pInfo	结构体数组首地址,用来存储设备序列号等信息的结构体数组。数组长度建议定义为50,
							//如:VCI_BOARD_INFO pInfo[50]。
//return DWORD			返回计算机中已插入的USB-CAN适配器的数量。
EXTERN_C DWORD  VCI_FindUsbDevice2(PVCI_BOARD_INFO pInfo);
/*
主要作用:
1、软件与硬件绑定:用户二次开发软件时,可以实现软件与硬件唯一绑定。通过调用该函
数,可以获取到设备的序列号,与用户应用程序预先设定的序列号对比。实现软件与硬件的
唯一绑定与加密。单台设备使用时,也可以直接用VCI_ReadBoardInfo函数填充的
VCI_BOARD_INFO结构体中的str_Serial_Num参数用于加密。
2、多卡同机时,设备索引号与序列号一一匹配:多台设备同时插在一台电脑时,要操作对
应设备,就需要知道此时对应设备的设备索引号。通过调用该函数,结构体数组pInfo中对
应的结构体中元素str_Serial_Num中即可保存所有设备的序列号,
pInfo[0].str_Serial_Num、pInfo[1].str_Serial_Num、pInfo[2].str_Serial_Num设备索
引号依次为0、1、2、3。
 */
#endif


/*
备注:
关于滤波器的设置,请参照:《9. 附件 2 : CAN 参数设置 .pdf》说明文档。
Timing0和Timing1用来设置CAN波特率,几种常见的波特率(采样点87.5%,SJW为0)
设置如下:
CAN波特率 Timing0(BTR0) Timing1(BTR1)
10 Kbps 0x31 0x1C
20 Kbps 0x18 0x1C
40 Kbps 0x87 0xFF
50 Kbps 0x09 0x1C
80 Kbps 0x83 0xFF
100 Kbps 0x04 0x1C
125 Kbps 0x03 0x1C
200 Kbps 0x81 0xFA
250 Kbps 0x01 0x1C
400 Kbps 0x80 0xFA
500 Kbps 0x00 0x1C
666 Kbps 0x80 0xB6
800 Kbps 0x00 0x16
1000 Kbps 0x00 0x14
33.33 Kbps 0x09 0x6F
66.66 Kbps 0x04 0x6F
83.33 Kbps 0x03 0x6F
注:
1.配置波特率时,用户只需要按照 SJA1000(16MHz)给的波特率参数进行设置
即可。
2.常规波特率直接按照上表的值配置即可。其它非常规波特率,可以使用附带
的波特率侦测工具进行侦测,并到得相应的波特率参数。或是使用USB_CAN TOOL
安装目录下的波特率计算工具计算。(参考《6.插件2:波特率侦测工具使用说明书.pdf》)
3.本适配器使用最新高速CAN收发器,不再支持10K以下波特率。



 pInitConfig
初始化参数结构。
参数成员列表:
成员
功能描述
由AccCode和AccMask可以共同决定哪些报文能
够被接受,这两个寄存器均采用ID的左对齐方式
pInitConfig->AccCode
设置,即AccCode与AccMask的最高位(Bit31)
与ID值的最高位对齐。
关于ID的对齐方式,请参照:
《 附件 1 : ID 对齐方
式详细说明 》说明文档。
例如: 若把AccCode的值设为0x24600000(即
0x123左移21位的结果), AccMask的值设为
0x00000000,则只有CAN信息帧ID为0x123的报
文能够被接受(AccMask的值0x00000000表示所
有 位 均 为 相 关 位 ) 。 若 把 AccCode 的 值 设 为
pInitConfig->AccMask
0x24600000,AccMask的值设为0x600000(0x03
左 移 21 位 的 结 果 ), 则 只 有 CAN 信 息 帧 ID 为
0x120~0x123的报文都能够被接受(AccMask的
值 0x600000 表 示 除 了 bit0~bit1 其 他 位
(bit2~bit10)均为相关位)。
注:本滤波器设置示例以标准帧为例,高11位
有效;若为扩展帧,则ID为29位,AccCode和
 AccMask设置时高29位对扩展帧有效!
保留
pInitConfig->Reserved
滤波方式的设置请参照本节的 滤波模式对照
pInitConfig->Filter
表 。
pInitConfig->Timing0 波特率 T0 设置
pInitConfig->Timing1 波特率 T1 设置
工作模式:
0-正常工作
pInitConfig->Mode
1-仅监听模式
2-自发自收测试模式
滤波模式对照表:
值 名称
说明
0/1 接收所有类型 滤波器同时对标准帧与扩展帧过滤!
2 只接收标准帧 滤波器只对标准帧过滤,扩展帧将直接被滤除。
3 只接收扩展帧 滤波器只对扩展帧过滤,标准帧将直接被滤除。
 */



