using ImTools; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace OrpaonEMS.App.CANDrive { /// /// CAN驱动 /// EMUC-B202-W1_CAN_API_V2.2.0_Win /// EMUC-B202-W1_CAN 有两个CAN口,目前工控机接出来的是CAN2口,那么调用和使用的时候使用CAN2口,在一些函数使用的过程中 /// 需要同时指定两个口的参数,那么另一个不适用的随便设置 /// public class CAN { const string LibName = @"C:\\CAN_inno\\EMUC-B202-W1_CAN_API_V2.2.0_Win\\2.0B_Lib_v2.2.0\\64\\lib_emuc2_64.dll"; /* load .dll */ [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCOpenDevice(int com_port); [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCCloseDevice(int com_port); /// /// Get firmware and library version /// /// /// /// [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCShowVer(int com_port, ref VER_INFO ver_info); [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCResetCAN(int com_port); [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCClearFilter(int com_port, int CAN_port); /// /// Set CAN port to active/inactive. Default is inactive. /// /// /// /// /// [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCInitCAN(int com_port, int CAN1_sts, int CAN2_sts); [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCSetBaudRate(int com_port, int CAN1_baud, int CAN2_baud); [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCSetMode(int com_port, int CAN1_mode, int CAN2_mode); [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCSetFilter(int com_port, ref FILTER_INFO filter_info); [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCSetErrorType(int com_port, int err_type); /// /// Set CAN acceptance filter /// /// /// /// [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCGetCfg(int com_port, ref CFG_INFO cfg_info); [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCExpCfg(int com_port, [MarshalAs(UnmanagedType.LPStr)] string file_name); [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCImpCfg(int com_port, [MarshalAs(UnmanagedType.LPStr)] string file_name); [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCSend(int com_port, ref CAN_FRAME_INFO can_frame_info); [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCReceive(int com_port, ref CAN_FRAME_INFO can_frame_info); [DllImport(LibName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int EMUCReceiveNonblockCS(int com_port, uint cnt, uint interval, [Out] CAN_FRAME_INFO[] can_frame_info); /// /// 实例化函数 /// public CAN() { } /// /// Can连接 /// /// public static bool ConnectionCan(BaudRate ConBaudRate) { int i; int j; //返回值 int rtn; //获取Com口给Global Global.com_port = FindEmucDev(); if (Global.com_port >= 0) { Console.WriteLine("EMUC open device (COM {0}) successfully !\n", Global.com_port + 1); /* ----- EMUCInitCAN() ----- */ rtn = EMUCInitCAN(Global.com_port, CANStatus.EMUC_INACTIVE.GetHashCode(), CANStatus.EMUC_INACTIVE.GetHashCode()); if (rtn == 0) Console.WriteLine("EMUC initial CAN successfully !\n"); else Console.WriteLine("EMUC initial CAN failed !\n"); /* ----- EMUCShowVer() ----- */ rtn = EMUCShowVer(Global.com_port, ref Global.ver_info); if (rtn == 0) { Console.WriteLine("EMUC show version successfully !"); Console.WriteLine("FW ver: {0}", Global.ver_info.fw); Console.WriteLine("LIB ver: {0}", Global.ver_info.api); Console.WriteLine("Model: {0}\n", Global.ver_info.model); } else Console.WriteLine("EMUC show version failed !\n"); /* ----- EMUCResetCAN() ----- */ rtn = EMUCResetCAN(Global.com_port); if (rtn == 0) Console.WriteLine("EMUC reset CAN successfully !\n"); else Console.WriteLine("EMUC reset CAN failed !\n"); /* ----- EMUCClearFilter() ----- */ Global.CAN_port = CANPort.EMUC_CAN_2.GetHashCode(); rtn = EMUCClearFilter(Global.com_port, Global.CAN_port); if (rtn == 0) Console.WriteLine("EMUC clear filter successfully !\n"); else Console.WriteLine("EMUC clear filter failed !\n"); /* ----- EMUCSetBaudRate() ----- */ rtn = EMUCSetBaudRate(Global.com_port, ConBaudRate.GetHashCode(), ConBaudRate.GetHashCode()); if (rtn == 0) Console.WriteLine("EMUC set baud rate successfully !\n"); else Console.WriteLine("EMUC set baud rate failed !\n"); /* ----- EMUCSetErrorType() ----- */ rtn = EMUCSetErrorType(Global.com_port, ErrType.EMUC_DIS_ALL.GetHashCode()); if (rtn == 0) Console.WriteLine("EMUC set error type successfully !\n"); else Console.WriteLine("EMUC set error type failed !\n"); /* ----- EMUCSetMode() ----- */ rtn = EMUCSetMode(Global.com_port, CANMode.EMUC_NORMAL.GetHashCode(), CANMode.EMUC_NORMAL.GetHashCode()); if (rtn == 0) Console.WriteLine("EMUC set mode successfully !\n"); else Console.WriteLine("EMUC set mode failed !\n"); /* ----- CAN1的设置 EMUCSetFilter() ----- */ Global.filter_info.CAN_port = CANPort.EMUC_CAN_1.GetHashCode(); Global.filter_info.flt_type = IDType.EMUC_SID.GetHashCode(); Global.filter_info.flt_id = 0x0000ABCD; Global.filter_info.mask = 0x1FFFFFFF; rtn = EMUCSetFilter(Global.com_port, ref Global.filter_info); if (rtn == 0) Console.WriteLine("EMUC set CAN 1 filter successfully !\n"); else Console.WriteLine("EMUC set CAN 1 filter failed !\n"); /* ----- CAN2的设置 EMUCSetFilter() ----- */ Global.filter_info.CAN_port = CANPort.EMUC_CAN_2.GetHashCode(); Global.filter_info.flt_type = IDType.EMUC_SID.GetHashCode(); Global.filter_info.flt_id = 0x00000000; Global.filter_info.mask = 0x00000000; rtn = EMUCSetFilter(Global.com_port, ref Global.filter_info); if (rtn == 0) Console.WriteLine("EMUC set CAN 2 filter successfully !\n"); else Console.WriteLine("EMUC set CAN 2 filter failed !\n"); /* ----- EMUCGetCfg() ----- */ /* ----- 获取配置信息----- */ rtn = EMUCGetCfg(Global.com_port, ref Global.cfg_info); if (rtn == 0) { Console.WriteLine("EMUC get config. successfully !"); for (i = 0; i < Global.CAN_NUM; i++) { Console.WriteLine("CAN {0}:", i + 1); Console.WriteLine("baud rate = {0}", Global.cfg_info.baud[i]); Console.WriteLine("mode = {0}", Global.cfg_info.mode[i]); Console.WriteLine("filter type = {0}", Global.cfg_info.flt_type[i]); Console.WriteLine("filter id = {0:X8}", Global.cfg_info.flt_id[i]); Console.WriteLine("filter mask = {0:X8}\n", Global.cfg_info.flt_mask[i]); } Console.WriteLine("error set = {0}\n", Global.cfg_info.err_set); } else Console.WriteLine("EMUC get config. failed !\n"); /* Send & Receive must initial CAN to EMUC_ACTIVE */ /*---------------------------------------------------------------------------*/ //EMUCClearFilter(Global.com_port, CANPort.EMUC_CAN_1.GetHashCode()); /* not necessary */ //EMUCClearFilter(Global.com_port, CANPort.EMUC_CAN_2.GetHashCode()); /* not necessary */ rtn = EMUCInitCAN(Global.com_port, CANStatus.EMUC_ACTIVE.GetHashCode(), CANStatus.EMUC_ACTIVE.GetHashCode()); if (rtn == 0) { return true; } else { return false; } } else Console.WriteLine("No EMUC device !\n"); return false; } /// /// 发送数据 /// public static bool SendData(uint id, byte[] data) { //int i; /* ----- EMUCSend ----- */ Global.frame_send.CAN_port = CANPort.EMUC_CAN_2.GetHashCode();//默认使用CAN2口 Global.frame_send.id_type = IDType.EMUC_EID.GetHashCode();//默认使用标准帧 Global.frame_send.rtr = RTRSelect.EMUC_DIS_RTR.GetHashCode();//默认使用数据帧,不是远程数据帧 Global.frame_send.dlc = 8;//默认数据长度为8 //Global.frame_send.id = 0x00000011; Global.frame_send.id = id; //Global.frame_send.data = Global.data_send; Global.frame_send.data = data; //Console.WriteLine("EMUC send started !"); //for (i = 0; i < Global.data_send_cnt; i++) //{ // Thread.Sleep(1); if (EMUCSend(Global.com_port, ref Global.frame_send) == 0) { //Console.WriteLine("EMUC send finished !\n", Global.data_send_cnt); return true; } return false; //EMUCSend(Global.com_port, ref Global.frame_send); //} Console.WriteLine("EMUC send finished (with {0} data) !\n", Global.data_send_cnt); } /// ///接受到的消息内容 /// public static void Start() { /* ----- EMUCReceive() ----- */ Global.TRDRecv.Start(); Console.WriteLine("\nEMUC reveice start ...\n"); } public void StartTest() { int i; int j; //返回值 int rtn; /* for EMUCReceiveNonblockCS() */ uint cnt; uint interval; CAN_FRAME_INFO[] frame_non_block; /*-----------------------------*/ //获取Com口给Global Global.com_port = FindEmucDev(); if (Global.com_port >= 0) { Console.WriteLine("EMUC open device (COM {0}) successfully !\n", Global.com_port + 1); /* ----- EMUCInitCAN() ----- */ rtn = EMUCInitCAN(Global.com_port, CANStatus.EMUC_INACTIVE.GetHashCode(), CANStatus.EMUC_INACTIVE.GetHashCode()); if (rtn == 0) Console.WriteLine("EMUC initial CAN successfully !\n"); else Console.WriteLine("EMUC initial CAN failed !\n"); /* ----- EMUCShowVer() ----- */ rtn = EMUCShowVer(Global.com_port, ref Global.ver_info); if (rtn == 0) { Console.WriteLine("EMUC show version successfully !"); Console.WriteLine("FW ver: {0}", Global.ver_info.fw); Console.WriteLine("LIB ver: {0}", Global.ver_info.api); Console.WriteLine("Model: {0}\n", Global.ver_info.model); } else Console.WriteLine("EMUC show version failed !\n"); /* ----- EMUCResetCAN() ----- */ rtn = EMUCResetCAN(Global.com_port); if (rtn == 0) Console.WriteLine("EMUC reset CAN successfully !\n"); else Console.WriteLine("EMUC reset CAN failed !\n"); /* ----- EMUCClearFilter() ----- */ Global.CAN_port = CANPort.EMUC_CAN_1.GetHashCode(); rtn = EMUCClearFilter(Global.com_port, Global.CAN_port); if (rtn == 0) Console.WriteLine("EMUC clear filter successfully !\n"); else Console.WriteLine("EMUC clear filter failed !\n"); /* ----- EMUCSetBaudRate() ----- */ rtn = EMUCSetBaudRate(Global.com_port, BaudRate.EMUC_BAUDRATE_1M.GetHashCode(), BaudRate.EMUC_BAUDRATE_1M.GetHashCode()); if (rtn == 0) Console.WriteLine("EMUC set baud rate successfully !\n"); else Console.WriteLine("EMUC set baud rate failed !\n"); /* ----- EMUCSetErrorType() ----- */ rtn = EMUCSetErrorType(Global.com_port, ErrType.EMUC_DIS_ALL.GetHashCode()); if (rtn == 0) Console.WriteLine("EMUC set error type successfully !\n"); else Console.WriteLine("EMUC set error type failed !\n"); /* ----- EMUCSetMode() ----- */ rtn = EMUCSetMode(Global.com_port, CANMode.EMUC_NORMAL.GetHashCode(), CANMode.EMUC_NORMAL.GetHashCode()); if (rtn == 0) Console.WriteLine("EMUC set mode successfully !\n"); else Console.WriteLine("EMUC set mode failed !\n"); /* ----- EMUCSetFilter() ----- */ Global.filter_info.CAN_port = CANPort.EMUC_CAN_1.GetHashCode(); Global.filter_info.flt_type = IDType.EMUC_EID.GetHashCode(); Global.filter_info.flt_id = 0x0000ABCD; Global.filter_info.mask = 0x1FFFFFFF; rtn = EMUCSetFilter(Global.com_port, ref Global.filter_info); if (rtn == 0) Console.WriteLine("EMUC set CAN 1 filter successfully !\n"); else Console.WriteLine("EMUC set CAN 1 filter failed !\n"); Global.filter_info.CAN_port = CANPort.EMUC_CAN_2.GetHashCode(); Global.filter_info.flt_type = IDType.EMUC_EID.GetHashCode(); Global.filter_info.flt_id = 0x00001234; Global.filter_info.mask = 0x00FFEEEE; rtn = EMUCSetFilter(Global.com_port, ref Global.filter_info); if (rtn == 0) Console.WriteLine("EMUC set CAN 2 filter successfully !\n"); else Console.WriteLine("EMUC set CAN 2 filter failed !\n"); /* ----- EMUCGetCfg() ----- */ rtn = EMUCGetCfg(Global.com_port, ref Global.cfg_info); if (rtn == 0) { Console.WriteLine("EMUC get config. successfully !"); for (i = 0; i < Global.CAN_NUM; i++) { Console.WriteLine("CAN {0}:", i + 1); Console.WriteLine("baud rate = {0}", Global.cfg_info.baud[i]); Console.WriteLine("mode = {0}", Global.cfg_info.mode[i]); Console.WriteLine("filter type = {0}", Global.cfg_info.flt_type[i]); Console.WriteLine("filter id = {0:X8}", Global.cfg_info.flt_id[i]); Console.WriteLine("filter mask = {0:X8}\n", Global.cfg_info.flt_mask[i]); } Console.WriteLine("error set = {0}\n", Global.cfg_info.err_set); } else Console.WriteLine("EMUC get config. failed !\n"); /* ----- EMUCExpCfg() ----- */ rtn = EMUCExpCfg(Global.com_port, Global.file_name); if (rtn == 0) Console.WriteLine("EMUC export config. successfully !\n"); else Console.WriteLine("EMUC export config. failed !\n"); /* ----- EMUCImpCfg() ----- */ rtn = EMUCImpCfg(Global.com_port, Global.file_name); if (rtn == 0) Console.WriteLine("EMUC import config. successfully !\n"); else Console.WriteLine("EMUC import config. failed !\n"); /* Send & Receive must initial CAN to EMUC_ACTIVE */ /*---------------------------------------------------------------------------*/ EMUCClearFilter(Global.com_port, CANPort.EMUC_CAN_1.GetHashCode()); /* not necessary */ EMUCClearFilter(Global.com_port, CANPort.EMUC_CAN_2.GetHashCode()); /* not necessary */ EMUCInitCAN(Global.com_port, CANStatus.EMUC_ACTIVE.GetHashCode(), CANStatus.EMUC_ACTIVE.GetHashCode()); /* ----- EMUCSend ----- */ Global.frame_send.CAN_port = CANPort.EMUC_CAN_1.GetHashCode(); Global.frame_send.id_type = IDType.EMUC_EID.GetHashCode(); Global.frame_send.rtr = RTRSelect.EMUC_DIS_RTR.GetHashCode(); Global.frame_send.dlc = 8; Global.frame_send.id = 0x001234AB; Global.frame_send.data = Global.data_send; Console.WriteLine("EMUC send started !"); for (i = 0; i < Global.data_send_cnt; i++) { Thread.Sleep(1); EMUCSend(Global.com_port, ref Global.frame_send); } Console.WriteLine("EMUC send finished (with {0} data) !\n", Global.data_send_cnt); /* ----- EMUCReceiveNonblock() ----- */ cnt = 5; interval = 5 * 1000; frame_non_block = new CAN_FRAME_INFO[cnt]; Console.WriteLine("Non-block ---------------------> Time start !"); rtn = EMUCReceiveNonblockCS(Global.com_port, cnt, interval, frame_non_block); if (rtn > 0) { Console.WriteLine("Non-block ---------------------> Time out or Data enough !\n"); for (i = 0; i < rtn; i++) { switch (frame_non_block[i].msg_type) { case (int)MsgType.EMUC_DATA_TYPE: PrintData(frame_non_block[i]); break; case (int)MsgType.EMUC_EEERR_TYPE: Console.WriteLine("EEPROM Error !"); break; case (int)MsgType.EMUC_BUSERR_TYPE: Console.WriteLine("Bus Error !"); System.Console.Write("error data (CAN 1): "); for (j = 0; j < Global.DATA_LEN_ERR; j++) System.Console.Write("{0:X2} ", frame_non_block[i].data_err[j]); Console.WriteLine(); System.Console.Write("error data (CAN 2): "); for (j = 0; j < Global.DATA_LEN_ERR; j++) System.Console.Write("{0:X2} ", frame_non_block[i].data_err[j + Global.DATA_LEN_ERR]); Console.WriteLine(); break; default: break; } } } else Console.WriteLine("Non-block ---------------------> Time out (No data) !\n"); /* ----- EMUCReceive() ----- */ Global.TRDRecv.Start(); Console.WriteLine("\nEMUC reveice start ...\n"); /* ----- EMUCCloseDevice() ----- */ /* rtn = EMUCCloseDevice(Global.com_port); if(rtn == 0) Console.WriteLine("EMUC close device (COM {0}) successfully !\n", Global.com_port + 1); else Console.WriteLine("EMUC close device failed !\n"); */ while (true) Thread.Sleep(10000); } else Console.WriteLine("No EMUC device !\n"); Console.ReadLine(); } #region 原始方法 /* success: return COM ID, failed: return -1 */ /*---------------------------------------------------------------------*/ /// /// 打开后返回对应的Com口 /// 返回Com口的ID /// /// public static int FindEmucDev() { int i; int rtn = -1; for (i = 0; i < Global.MAX_COM_NUM; i++) { if (EMUCOpenDevice(i) == 0) { rtn = i; break; } } return rtn; } /* END: FindEmucDev() */ /*---------------------------------------------------------------------*/ /// /// 循环接受数据 /// public static void TRDRecvFx() { int i; int rtn; while (true) { rtn = EMUCReceive(Global.com_port, ref Global.frame_recv); if (rtn == 1) { switch (Global.frame_recv.msg_type) { case (int)MsgType.EMUC_DATA_TYPE: PrintData(Global.frame_recv); switch (Global.frame_recv.id) { case 402686016://ID(0x18008040) ACCANParsData.Load_0x18008040_Msg(Global.frame_recv); break; case 402751552://ID(0x18018040) ACCANParsData.Load_0x18018040_Msg(Global.frame_recv); break; default: break; } break; case (int)MsgType.EMUC_EEERR_TYPE: Console.WriteLine("EEPROM Error !"); break; case (int)MsgType.EMUC_BUSERR_TYPE: //Console.WriteLine("Bus Error !"); //System.Console.Write("error data (CAN 1): "); //for (i = 0; i < Global.DATA_LEN_ERR; i++) // //System.Console.Write("{0:X2} ", Global.frame_recv.data_err[i]); ////Console.WriteLine(); //System.Console.Write("error data (CAN 2): "); //for (i = 0; i < Global.DATA_LEN_ERR; i++) // //System.Console.Write("{0:X2} ", Global.frame_recv.data_err[i + Global.DATA_LEN_ERR]); ////Console.WriteLine(); break; default: break; } } } } /* END: TRDRecvFx() */ public static void ParseData(byte[] data) { } /*---------------------------------------------------------------------*/ /// /// 打印数据 /// /// public static void PrintData(CAN_FRAME_INFO frame_recv) { int i; /* CAN port & cnt */ if (frame_recv.CAN_port == CANPort.EMUC_CAN_1.GetHashCode()) { Global.recv_cnt1++; //System.Console.Write("(CAN 1) {0}. ", Global.recv_cnt1); } else if (frame_recv.CAN_port == CANPort.EMUC_CAN_2.GetHashCode()) { Global.recv_cnt2++; //System.Console.Write("(CAN 2) {0}. ", Global.recv_cnt2); } /* ID */ //if (frame_recv.id_type == IDType.EMUC_SID.GetHashCode()) //System.Console.Write("ID: {0:X3}; ", frame_recv.id); //else if (frame_recv.id_type == IDType.EMUC_EID.GetHashCode()) //System.Console.Write("ID: {0:X8}; ", frame_recv.id); /* Data */ //System.Console.Write("Data: "); //for (i = 0; i < frame_recv.dlc; i++) //System.Console.Write("{0:X2} ", frame_recv.data[i]); //Console.WriteLine(); } /* END: PrintData() */ #endregion /* global variables */ public class Global { /// /// 设备最大的COM数 /// public const int MAX_COM_NUM = 256; public const int CAN_NUM = 2; public const int DATA_LEN = 8; public const int DATA_LEN_ERR = 6; /// /// Com口 /// -1是失败的 /// public static int com_port { get; set; } /// /// CAN口 /// public static int CAN_port { get; set; } [MarshalAs(UnmanagedType.LPStr)] public static string file_name = "emuc_config"; public static int data_send_cnt = 500; public static byte[] data_send = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 }; public static uint recv_cnt1 = 0; public static uint recv_cnt2 = 0; /// /// 版本信息 /// public static VER_INFO ver_info = new VER_INFO(); /// /// 过滤信息 /// public static FILTER_INFO filter_info = new FILTER_INFO(); public static CFG_INFO cfg_info = new CFG_INFO(); public static CAN_FRAME_INFO frame_send = new CAN_FRAME_INFO(); public static CAN_FRAME_INFO frame_recv = new CAN_FRAME_INFO(); public static Thread TRDRecv = new Thread(TRDRecvFx); } } /* structure */ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct VER_INFO { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string fw; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string api; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string model; } /// /// /// CAN标识符、过滤器、屏蔽器之间的关系 ///CAN节点通过标识符来识别CAN帧是不是自己想要的,识别方法就是通过滤波屏蔽寄存器的设置来完成,接收滤波寄存器设置了标识符每位的值, ///接收屏蔽寄存器一般有相同的数量匹配接收滤波寄存器,规定接收滤波寄存器标识符每一位的值是否需要进行匹配,比如芯片设置有6个接收滤波寄存器和6个接收屏蔽青存器, ///从总线上接收 CAN 帧,然后依次将收到的 CAN 帧标识符与6对接收滤波和屏蔽寄存器进行匹配,符合某对接收滤波和屏蔽寄存器要求了,就停止匹配,将数据接收到对应的缓冲区中.. ///例如:设置某接收滤波寄存器 00000000001(11 位),接收屏蔽寄存器 11111111101(11 位),则该对组合会拒绝接收 00000000011和 00000000001 之外所有的标识符对应的 CAN 帧, ///因为屏蔽器规定第二位(为 0)以外的所有标识符位要严格匹配(与滤波器值一致),第二位的滤波器值和收到的 CAN 标识符第二位值是否一致都可以。 /// https://www.cnblogs.com/lijf/p/17418979.html ///对于机器来说,我们要为它准备好两张纸片,一片写上屏蔽码,另一片纸片写上验证码,屏蔽码上相应位为1时,表示此位需要与验证码对应位进行比较,反之,则表示不需要。机器在执行任务的时候先将获取的身份证号码与屏蔽码进行“与”操作,再将结果与验证码的进行比较,根据判断是否相同来决定是否通过。整个判别流程如下所示: ///从上图可以很容易地理解屏蔽码与验证码的含义,这样一来,能通过的结果数量就完全取决于屏蔽码,设得宽,则可以通过的多(所有位为0,则不过任何过滤操作,则谁都可以通过),设得窄,则通过的少(所有位设为1,则只有一个能通过)。那么知道这个有什么用呢?因为bxCAN的过滤器的掩码模式就是采用这种方式,在bxCAN中,分别采用了两个寄存器(CAN_FiR1,CAN_FiR2)来存储屏蔽码与验证码,从而实现掩码模式的工作流程的。这样,我们就知道了bxCAN过滤器的掩码模式的大概工作原理。 /// /// [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct FILTER_INFO { public int CAN_port; /// /// 过滤类型/方式 /// 比如:只收标准码,只收拓展码,接受所有类型 /// public int flt_type; /// /// 过滤验收码 /// 就是要接收的帧ID /// public uint flt_id; /// /// 过滤屏蔽码 /// 就是选择性的过滤帧ID。 /// 当屏蔽码的某一位为1时,则忽略此位,此位不需要与验收码一致。当屏蔽码的某一位为0时,此位必须与验收码的此位一致。 /// public uint mask; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct CFG_INFO { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] baud; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] mode; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] flt_type; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public uint[] flt_id; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public uint[] flt_mask; public byte err_set; } #region 结构体和枚举 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct CAN_FRAME_INFO { /// /// 哪个端口发送的 /// 当前的CAN模块有两个端口 /// public int CAN_port; /// /// : [input] CAN ID type. (SID=11bit, EID=29bit) /// 标准还是拓展 /// public int id_type; /// /// [input] Remote transmit request /// 远程还是数据帧 /// public int rtr; /// /// dlc: [input] Data length. /// 数据长度 /// public int dlc; /// /// There three types of received data define in msg_type. //1. EMUC_DATA_TYPE: Normal CAN frame. //2. EMUC_EEERR_TYPE: EEPROM error message. //3. EMUC_BUSERR_TYPE: Register of CANbus error status. /// public int msg_type; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 13)] public string recv_time; /* e.g., 15:30:58:789 (h:m:s:ms) */ /// /// 帧Id /// public uint id; /// /// 接受的数据 /// [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] data; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] data_err; } /* enumeration */ enum CANPort : int { /// /// CAN1 /// EMUC_CAN_1 = 0, /// /// CAN2 /// EMUC_CAN_2 }; /*----------------------*/ public enum BaudRate : int { EMUC_BAUDRATE_100K = 4, EMUC_BAUDRATE_125K, EMUC_BAUDRATE_250K, EMUC_BAUDRATE_500K, EMUC_BAUDRATE_800K, EMUC_BAUDRATE_1M }; /*----------------------*/ enum CANStatus : int { /// /// 默认 /// 未激活 /// EMUC_INACTIVE = 0, /// /// 激活 /// EMUC_ACTIVE }; /*----------------------*/ enum CANMode : int { /// /// 正常 /// EMUC_NORMAL = 0, /// /// 监听(只听)模式 /// EMUC_LISTEN }; /*----------------------*/ /// /// 过滤类型/方式 /// /// 比如:只收标准码,只收拓展码,接受所有类型 /// /// ***也可以作为发送时的帧的类型的*** /// public enum IDType : int { //0可能是接受所有类型 /// /// SID=11bit /// 标准帧 /// EMUC_SID = 1, /// /// EID=29bit /// Extended Mode /// 拓展帧 /// EMUC_EID }; /*----------------------*/ enum RTRSelect : int { /// /// 取消使用RTR /// 普通的 /// 数据帧 /// EMUC_DIS_RTR = 0, /// /// 启用RTR /// 远程帧 /// EMUC_EN_RTR }; /*----------------------*/ /// /// CAN Error Frame /// enum ErrType : int { /// /// disable all error frame /// EMUC_DIS_ALL = 0, /// /// enable EEPROM error only /// EMUC_EE_ERR, /// /// enable CAN bus error only /// EMUC_BUS_ERR, /// /// enable both EERPOM and CAN bus error /// EMUC_EN_ALL = 255 }; /*----------------------*/ /// /// There three types of received data define in msg_type /// enum MsgType : int { /// /// Normal CAN frame /// EMUC_DATA_TYPE = 0, /// /// EEPROM error message /// EMUC_EEERR_TYPE, /// /// : Register of CANbus error status /// EMUC_BUSERR_TYPE }; #endregion }