用electron做一个访问can卡的上位机
使用node-ffi-napi 访问dll文件,需要安装
ffi-napi
ref-napi
ref-array-napi
ref-struct-napi
安装ffi需要用到node-gyp,安装教程可以百度下
以下是使用过程
需要调用的dll的.h头文件如下,此dll是用来访问can卡的
#ifndef CONTROLCAN_H
#define CONTROLCAN_H
//#include <cvidef.h> //使用CVI平台开发,请使用该语句。
//接口卡类型定义
#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
//1.ZLGCAN系列接口卡信息的数据类型。
typedef struct _VCI_BOARD_INFO{
USHORT hw_Version;
USHORT fw_Version;
USHORT dr_Version;
USHORT in_Version;
USHORT irq_Num;
BYTE can_Num;
CHAR str_Serial_Num[20];
CHAR str_hw_Type[40];
USHORT Reserved[4];
} VCI_BOARD_INFO,*PVCI_BOARD_INFO;
//2.定义CAN信息帧的数据类型。
typedef struct _VCI_CAN_OBJ{
UINT ID;
UINT TimeStamp;
BYTE TimeFlag;
BYTE SendType;
BYTE RemoteFlag;//是否是远程帧
BYTE ExternFlag;//是否是扩展帧
BYTE DataLen;
BYTE Data[8];
BYTE Reserved[3];
}VCI_CAN_OBJ,*PVCI_CAN_OBJ;
//3.定义初始化CAN的数据类型
typedef struct _VCI_INIT_CONFIG{
DWORD AccCode;
DWORD AccMask;
DWORD Reserved;
UCHAR Filter;
UCHAR Timing0;
UCHAR Timing1;
UCHAR Mode;
}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;
#define EXTERNC extern "C"
EXTERNC DWORD __stdcall VCI_OpenDevice(DWORD DeviceType,DWORD DeviceInd,DWORD Reserved);
EXTERNC DWORD __stdcall VCI_CloseDevice(DWORD DeviceType,DWORD DeviceInd);
EXTERNC DWORD __stdcall VCI_InitCAN(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd, PVCI_INIT_CONFIG pInitConfig);
EXTERNC DWORD __stdcall VCI_ReadBoardInfo(DWORD DeviceType,DWORD DeviceInd,PVCI_BOARD_INFO pInfo);
EXTERNC DWORD __stdcall VCI_SetReference(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,DWORD RefType,PVOID pData);
EXTERNC ULONG __stdcall VCI_GetReceiveNum(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC DWORD __stdcall VCI_ClearBuffer(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC DWORD __stdcall VCI_StartCAN(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC DWORD __stdcall VCI_ResetCAN(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC ULONG __stdcall VCI_Transmit(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_OBJ pSend,ULONG Len);
EXTERNC ULONG __stdcall VCI_Receive(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_OBJ pReceive,ULONG Len,INT WaitTime);
/*------------------------------------------------其他补充函数及数据结构描述------------------------------------------------*/
//USB-CAN总线适配器板卡信息的数据类型1,该类型为VCI_FindUsbDevice函数的返回参数。
typedef struct _VCI_BOARD_INFO1{
USHORT hw_Version;
USHORT fw_Version;
USHORT dr_Version;
USHORT in_Version;
USHORT irq_Num;
BYTE can_Num;
BYTE Reserved;
CHAR str_Serial_Num[8];
CHAR str_hw_Type[16];
CHAR str_Usb_Serial[4][4];
} VCI_BOARD_INFO1,*PVCI_BOARD_INFO1;
//USB-CAN总线适配器板卡信息的数据类型2,该类型为VCI_FindUsbDevice函数的返回参数。为扩展更多的设备
typedef struct _VCI_BOARD_INFO2{
USHORT hw_Version;
USHORT fw_Version;
USHORT dr_Version;
USHORT in_Version;
USHORT irq_Num;
BYTE can_Num;
BYTE Reserved;
CHAR str_Serial_Num[8];
CHAR str_hw_Type[16];
CHAR str_Usb_Serial[10][4];
} VCI_BOARD_INFO2,*PVCI_BOARD_INFO2;
#define EXTERNC extern "C"
EXTERNC DWORD __stdcall VCI_GetReference2(DWORD DevType,DWORD DevIndex,DWORD CANIndex,DWORD Reserved,BYTE *pData);
EXTERNC DWORD __stdcall VCI_SetReference2(DWORD DevType,DWORD DevIndex,DWORD CANIndex,DWORD RefType,BYTE *pData);
EXTERNC DWORD __stdcall VCI_ConnectDevice(DWORD DevType,DWORD DevIndex);
EXTERNC DWORD __stdcall VCI_UsbDeviceReset(DWORD DevType,DWORD DevIndex,DWORD Reserved);
EXTERNC DWORD __stdcall VCI_FindUsbDevice(PVCI_BOARD_INFO1 pInfo);
EXTERNC DWORD __stdcall VCI_FindUsbDevice2(PVCI_BOARD_INFO2 pInfo);
#endif
nodejs中安装完成下列包
"dependencies": {
"ffi-napi": "^3.1.0",
"ref-array-napi": "^1.2.1",
"ref-napi": "^3.0.1",
"ref-struct-napi": "^1.1.1"
}
然后在js文件中使用 (注释和解释在代码中)
dll 的调用需要注意dll是64位还是32位的
这里nodejs是64位的,dll也是64位的
否则可能报错
let ffi = require("ffi-napi");
let ref = require('ref-napi');
let ArrayType = require('ref-array-napi');
let StructType = require('ref-struct-napi');
let _VCI_BOARD_INFO = StructType({ //定义结构体
hw_Version: ref.types.ushort,
fw_Version: ref.types.ushort,
dr_Version: ref.types.ushort,
in_Version: ref.types.ushort,
irq_Num: ref.types.ushort,
can_Num: ref.types.byte,
str_Serial_Num: ArrayType(ref.types.char, 20), //char str_Serial_Num[20]
str_hw_Type: ArrayType(ref.types.char, 40),
Reserved: ArrayType(ref.types.ushort, 4),
})
let _VCI_CAN_OBJ = StructType({ //定义结构体
ID: ref.types.uint,
TimeStamp: ref.types.uint,
TimeFlag: ref.types.byte,
SendType: ref.types.byte,
RemoteFlag: ref.types.byte,
ExternFlag: ref.types.byte,
DataLen: ref.types.byte,
Data: ArrayType(ref.types.byte, 8),
Reserved: ArrayType(ref.types.byte, 3),
})
let _VCI_INIT_CONFIG = StructType({ //定义结构体
AccCode: ref.types.ulong, //DWORD 就是 ref.types.ulong
AccMask: ref.types.ulong,
Reserved: ref.types.ulong,
Filter: ref.types.uchar,
Timing0: ref.types.uchar,
Timing1: ref.types.uchar,
Mode: ref.types.uchar,
})
let _VCI_FILTER_RECORD = StructType({ //定义结构体
ExtFrame: ref.types.ulong,
Start: ref.types.ulong,
End: ref.types.ulong,
})
let _VCI_BOARD_INFO1 = StructType({ //定义结构体
hw_Version: ref.types.ushort,
fw_Version: ref.types.ushort,
dr_Version: ref.types.ushort,
in_Version: ref.types.ushort,
irq_Num: ref.types.ushort,
can_Num: ref.types.byte,
Reserved: ref.types.byte,
str_Serial_Num: ArrayType(ref.types.char, 8),
str_hw_Type: ArrayType(ref.types.char, 16),
str_Usb_Serial: ArrayType(ArrayType(ref.types.char, 4), 4), //char str_Usb_Serial[4][4]
})
let _VCI_BOARD_INFO2 = StructType({ //定义结构体
hw_Version: ref.types.ushort,
fw_Version: ref.types.ushort,
dr_Version: ref.types.ushort,
in_Version: ref.types.ushort,
irq_Num: ref.types.ushort,
can_Num: ref.types.byte,
Reserved: ref.types.byte,
str_Serial_Num: ArrayType(ref.types.char, 8),
str_hw_Type: ArrayType(ref.types.char, 16),
str_Usb_Serial: ArrayType(ArrayType(ref.types.char, 10), 4), //char str_Usb_Serial[10][4]
})
let canDLL = ffi.Library('./ControlCAN.dll', { //定义方法
'VCI_OpenDevice': [ref.types.ulong, [ref.types.ulong, ref.types.ulong, ref.types.ulong]],
'VCI_CloseDevice': [ref.types.ulong, [ref.types.ulong, ref.types.ulong]],
'VCI_StartCAN': [ref.types.ulong, [ref.types.ulong, ref.types.ulong, ref.types.ulong]],
'VCI_ReadBoardInfo': [ref.types.ulong, [ref.types.ulong, ref.types.ulong, ref.refType(_VCI_BOARD_INFO)]],
'VCI_InitCAN': [ref.types.ulong, [ref.types.ulong, ref.types.ulong, ref.types.ulong, ref.refType(_VCI_INIT_CONFIG)]],
'VCI_FindUsbDevice': [ref.types.ulong, [ref.refType(_VCI_BOARD_INFO1)]]
})
//打开设备
let open = canDLL.VCI_OpenDevice(3, 0, 0) //传入3个DWORD
console.log(open)
//设备初始化
let initconfig = new _VCI_INIT_CONFIG({ //创建一个结构体并赋值
AccCode: 0x80000008,
AccCode: 0xFFFFFFFF,
Filter: 0,
Timing0: 0x03,
Timing1: 0x1c,
Mode: 0
});
let init = canDLL.VCI_InitCAN(3, 0, 0, initconfig.ref()) //传入3个dword和一个结构体指针
console.log(init)
//打开can
let startCan = canDLL.VCI_StartCAN(3, 0, 0);
console.log(startCan)
//打印接口卡信息
let boardinfo = new _VCI_BOARD_INFO(); //创建一个结构体
canDLL.VCI_ReadBoardInfo.async(3, 0, boardinfo.ref(), (err, result) => {
if (err) {
console.log(err)
}
console.log(result) //调用成功后,返回1
console.log("--------------接口卡信息------------------------")
console.log('hw_Version:'+boardinfo.hw_Version) //访问结构体内的值
console.log('fw_Version:'+boardinfo.fw_Version)
console.log('dr_Version:'+boardinfo.dr_Version)
console.log('in_Version:'+boardinfo.in_Version)
console.log('irq_Num:'+boardinfo.irq_Num)
console.log('can_Num:'+boardinfo.can_Num)
console.log(boardinfo.str_Serial_Num)
console.log(boardinfo.str_hw_Type)
console.log(boardinfo.Reserved)
})