用C#实现基于UDS的CAN上位机开发(二)

1.CAN数据的常规收发实现

常规数据的收发实现其实也不是很难,主要是根据CAN盒提供的二次开发库(一般为dll文件)和一些帮助文档(主要是介绍函数的使用,CAN盒的初始化顺序)在上位机中按照正确的顺序初始化CAN盒并开启,最后在一个线程中不断的调用接口函数获取数据。

关于CAN盒的选择主要有两种,一种是通过USB接口和PC通信的,这类CAN盒收发的速率比较高,也比较稳定,不容易出现丢帧的现象;另一类是通过串口的方式和PC通信,这种CAN盒的特点是相对便宜,原理上就一个MCU利用内部的CAN控制器模块和串口模块。CAN模块提供对外接口,串口模块负责和PC端通信,在我之前的开发中有用过这类CAN盒,收发速度不能太快,发送实际测试应该有每秒500帧-600帧。本次设计中选用USB通信的CAN盒。

2.CAN盒的使用

CAN盒选用的是某宝上200大洋左右的,实际使用中没遇到过丢帧的情况(测试环境是接收1百万帧的数据以每秒3千帧的速度)。根据其帮助文档,按顺序初始化设备。在我的设计中有两种开启设备方式,一种是在上位机开启时尝试初始化并开启。第二种是在上位机运行时通过菜单键手动设置,开启CAN盒。

3.资源的使用

实现收发功能,用到了两个线程,一个定时器,一个缓存显示收发数据的ringbuffer,datagridview等控件/资源。

线程1:用于CAN数据的接收,将接收到的数据放入ringbuffer中。

线程2:用于将收发数据加载到List中。

定时器:用于定时检测CAN盒的状态,计算收发速率。

RingBuffer:用于缓存要显示的收发数据。

Datagridview:用于显示收发的数据。

3.设计时的注意点

在这两个线程中都应该加入线程的sleep方法,避免CPU使用过高,另外sleep的时间不应过长,以防止数据接收不过来,实际中发现就算写成sleep(1),有时线程再切换回来已花费了十五左右毫秒,网上查找资料发现这是windows的问题,要解决这个问题得在sleep函数调用前后加上 void timeBeginPeriod(int t) 和 void timeEndPeriod(int t);参数t设置成1,此时线程切换就是1ms了,但不易过多的使用,因为会导致系统花费过多的资源在线程切换上。

计算收发速率时,本想着计算1秒钟内接收或发送的报文数量,但是由于定时器及其不稳,导致计算的速率错误。解决方法是应该测量这个定时器实际定时的时间,用这段时间内接收/发送的报文数量计算其收发速率。

用datagriidview显示数据时,在数据量较少时没什么问题,数据量大时会耗费大量的时间,通过调查发现主要原因是每次更新显示都是从新绑定List到datagridview,这会花费时间,另外由于我在每次更新时会将datagridview指向最后一行,虽说好看了些,但是这样消耗了一些时间。解决的方法是采用虚拟加载的方式,以及限定最大的收发显示数量,就是说当list的长度大于我设定的值时,当新增一个数据时,移除最前面的数据,这样在收发,查看数据时也不会发生卡顿的现象了。

4.功能测试

测试10万帧数据的接收,时间戳做的不好应该用CAN盒的时间来表示每帧数据真实的接收时间点,但是由于不好和发送的时间做统一,故而统一采用PC端的时间了?,这点以后可以改进。。。

用C#实现基于UDS的CAN上位机开发(二)_第1张图片

显示接收速率

用C#实现基于UDS的CAN上位机开发(二)_第2张图片

数据发送

用C#实现基于UDS的CAN上位机开发(二)_第3张图片

5.保存窗口参数

当窗口关闭时,把各个控件的属性值写入到XML文件中,加密保存,窗口打开时解密并解析xml,将各个控件的属性值初始化。

6.收发数据窗口的源码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
using System.IO;
using System.Text;
using System.Xml;

namespace XCAN
{
    public partial class XCAN : Form
    {
        const int RT_MaxNumber = 8000;//最大显示行数

        bool IsDisplayRate_Flag = false;//用于产生1S

        UInt16 CAN_Rate = 0;//can 波特率
        UInt16 OldCAN_Rate = 0;
        
        public const UInt32 m_devtype = 4;//设备类型,USBCAN2
        public const UInt32 m_devind = 0; //设备索引号,0
        private const UInt32 canbffersize = 2000;//can buffer

        ushort CAN_Status = 0;      //can盒设备开启(bit0),初始化(bit1),通道开启状态(bit2)
        ushort OldCAN_Status = 0x08;

        //uint R_HistoryTicks = 0;//时间戳
        //long T_HistoryTicks = 0;//时间戳
        //long FristEnterT_ticks = 0;
        //long FristEnterR_ticks = 0;

        long FristEnterRT_ticks = 0;

        //long LastTimeStamp = 0;

        //bool FirstEnterRcevDeal_Pec_Flag = true;
        //bool FirstEnterSendDeal_Pec_Flag = true;
        //UInt16 WhoFristEnterRTBuffer = 0;//标记R/T那个先进入RT_buffer

        bool Add_RT_DataToList_Flag = false;

        bool Is_RT_IDLE_Flag = false;

        public static bool Is_RT_ButtonTurnOn = true;

        public static bool UDS_ENABLE = false;    //UDS使能

        public static UInt32 m_bOpen = 0;        //设备启用
        public static UInt32 m_canind = 0;       //can 通道      

        UInt32 r_number = 0;//用于计算接收速率
        UInt32 t_number = 0;//用于计算发送速率

        public static UInt32 t_error_number = 0;//发送错误
        UInt32 r_sequence_number = 0;//指示收数据的编号
        public static UInt32 t_sequence_number = 0;//指示发数据的编号
        UInt32 rt_sequence_number = 0;//指示收发数据的编号

        VCI_CAN_OBJ[] m_recobj = new VCI_CAN_OBJ[canbffersize];

        public static List tr_can_information = new List();

        /*------------兼容ZLG的函数描述---------------------------------*/
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_OpenDevice(UInt32 DeviceType, UInt32 DeviceInd, UInt32 Reserved);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_CloseDevice(UInt32 DeviceType, UInt32 DeviceInd);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_InitCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_INIT_CONFIG pInitConfig);

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_ReadBoardInfo(UInt32 DeviceType, UInt32 DeviceInd, ref VCI_BOARD_INFO pInfo);

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_GetReceiveNum(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_ClearBuffer(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_StartCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_ResetCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_Transmit(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pSend, UInt32 Len);

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_Receive(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pReceive, UInt32 Len, Int32 WaitTime);

        /*-------------------------------------------------------其他函数描述----------------------------------------*/
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_ConnectDevice(UInt32 DevType, UInt32 DevIndex);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_UsbDeviceReset(UInt32 DevType, UInt32 DevIndex, UInt32 Reserved);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_FindUsbDevice(ref VCI_BOARD_INFO1 pInfo);
        /*--------------------------------------------------------函数描述结束----------------------------------------*/

        public XCAN()
        {
            InitializeComponent();
        }

        [DllImport("kernel32.dll")]
        public extern static short QueryPerformanceCounter(ref long x);


        [DllImport("kernel32.dll")]
        public extern static short QueryPerformanceFrequency(ref long x);
        private void Form1_Load(object sender, EventArgs e)
        {
            /* 初始化CAN配置参数显示 */

            bool UseLocalParameter = false;

            string XML_DecryptContent = null;
            try
            {
                StreamReader sr = new StreamReader("Form1_Cfg.xml", Encoding.Default);
                string XML_Content = sr.ReadToEnd();
                sr.Close();
                XML_DecryptContent = AES.AesDecrypt(XML_Content,"q1a2s3d4d5f6g7h8.");
            }
            catch
            {
                UseLocalParameter = true;
            }

            if (XML_DecryptContent == "")
            {
                UseLocalParameter = true;
            }

            XmlDocument xmlDoc = new XmlDocument();
            try
            {
                xmlDoc.LoadXml(XML_DecryptContent);
            }
            catch
            {
                UseLocalParameter = true;
            }

            XmlNodeList CfgNodeList = null;
            try
            {
                CfgNodeList = xmlDoc.SelectSingleNode("Form1_Cfg").ChildNodes;
            }
            catch
            {
                UseLocalParameter = true;
            }

            if (CfgNodeList != null)
            {
                foreach (XmlNode singleXmlNode in CfgNodeList)
                {
                    switch (singleXmlNode.Name)
                    {
                        case "label_frame_type": { combobox_frame_type.SelectedIndex = (singleXmlNode.InnerText == "1") ? 1 : 0; } break;
                        case "label_frame_format": { combobox_frame_format.SelectedIndex = (singleXmlNode.InnerText == "1") ? 1 : 0; } break;
                        case "label_frame_id": { textBox_frame_iden.Text = singleXmlNode.InnerText; } break;
                        case "label_frame_data": { textBox_frame_data.Text = singleXmlNode.InnerText; } break;
                        default: break;
                    }
                }
            }
            else
            {
                UseLocalParameter = true;
            }

            if(UseLocalParameter == true)
            {               
                combobox_frame_format.SelectedIndex = 0;//默认为数据帧
                combobox_frame_type.SelectedIndex = 0;  //默认为标准帧
                textBox_frame_iden.Text = "123";        //默认ID为0x123
                textBox_frame_data.Text = "12 13 14 15 16 17 18 19"; //默认的发送数据
            }       

            //设置列的宽度
            dataGridView1.Columns[0].Width = 65;
            dataGridView1.Columns[1].Width = 75;
            dataGridView1.Columns[2].Width = 90;
            dataGridView1.Columns[3].Width = 90;
            dataGridView1.Columns[4].Width = 85;
            dataGridView1.Columns[5].Width = 95;
            dataGridView1.Columns[6].Width = 100;
            dataGridView1.Columns[7].Width = 100;
            dataGridView1.Columns[8].Width = dataGridView1.Width - 700;//972-700 = 272
 
            /* 尝试打开设备,返回 1 ,0 ,-1 */
            UInt32 tval = opendevice();

            if(1== tval)//打开成功,清通道数据
            {
                VCI_INIT_CONFIG Tcan_confi;

                CAN_Status = (ushort)(CAN_Status | (0x01));//标记设备已开启 

                Tcan_confi.AccCode = 0x80000000;//过滤验收码
                Tcan_confi.AccMask = 0xFFFFFFFF;//过滤屏蔽码
                Tcan_confi.Filter = 1;//接收所有
                Tcan_confi.Mode = 0;//工作模式,正常
                Tcan_confi.Reserved = 0;

                Tcan_confi.Timing0 = 0x00;
                Tcan_confi.Timing1 = 0x1c;  //500k

                CAN_Rate = 500;

                setCAN_Praameter(Tcan_confi);
            }

            /* 创建一个接收线程 */
            Thread rec_th = new Thread(new ThreadStart(rec_can_message_TH));
            rec_th.Priority = ThreadPriority.AboveNormal;
            rec_th.IsBackground = true;
            rec_th.Start();

            /* 创建一个更新收发数据显示的线程 */
            Thread displayoriginaldata_th = new Thread(new ThreadStart(update_display_original_data_TH));
            displayoriginaldata_th.Priority = ThreadPriority.BelowNormal;
            displayoriginaldata_th.IsBackground = true;
            displayoriginaldata_th.Start();

            timer1_dispaly_500ms.Enabled = true;//开启定时显示,500ms

            Control.CheckForIllegalCrossThreadCalls = false;//(不推荐)
        }
        ///


        /// 输出提示信息
        ///

        ///
        private void MainWindows_Output_Reminder(string str)
        {
            label_mainwindow_reminder.Text = "提示:" + str + "!" + "(" + System.DateTime.Now.ToString("t") + ")";
        }
        /*
         * 毫秒->秒毫秒
         */
        private String Time_Frame_Conversion(long ms)
        {
            string conversion_value;
                        
            conversion_value = (ms/1000).ToString().PadLeft(4,'0')+":"+ (ms%1000).ToString().PadLeft(3, '0');

            return conversion_value;
        }
        ///


        /// 没有数据时,睡眠1ms
        ///

        private void update_display_original_data_TH()
        {
            long ticks_ms = 0;
            rec_send_info t_info;
            string T_rt = null;
            string T_timestamp = null;

            while (true)
            {
                if(true == rt_can_ringbuffer.ringbufferisempty())
                {
                    timeBeginPeriod(1);
                    Thread.Sleep(1);//休眠1ms
                    timeEndPeriod(1);
                }
                else
                {
                    RT_CANDATA_INFO Tdata = rt_can_ringbuffer.ringbuffergetone();

                    if (0xA5 == Tdata.RT_Index)//数据为发送
                    {
                        T_rt = "发送";                                      
                    }
                    else if(0x5A == Tdata.RT_Index)//数据为接收
                    {
                        T_rt = "接收";                                   
                    }
                    else
                    {
                        continue;
                    }

                    if (FristEnterRT_ticks > 0)
                    {
                        ticks_ms = ( DateTime.Now.Ticks - FristEnterRT_ticks) / 10000;
                    }
                    else
                    {
                        FristEnterRT_ticks = DateTime.Now.Ticks;
                        ticks_ms = 0;
                    }

                    T_timestamp = Time_Frame_Conversion(ticks_ms);

                    t_info.temp_can_id = "Ox" + System.Convert.ToString(Tdata.VCI_CAN_OBJ1.ID, 16).ToLower();

                    if (Tdata.VCI_CAN_OBJ1.RemoteFlag == 0)
                    {
                        t_info.tem_can_format = "数据帧 ";
                    }                       
                    else
                    {
                        t_info.tem_can_format = "远程帧 ";
                    }
                       
                    if (Tdata.VCI_CAN_OBJ1.ExternFlag == 0)
                    {
                        t_info.tem_can_type = "标准帧 ";
                    }                        
                    else
                    {
                        t_info.tem_can_type = "扩展帧 ";
                    }                        

                    t_info.tem_rt_ch = "CH" + m_canind.ToString();

                    byte len = (byte)(Tdata.VCI_CAN_OBJ1.DataLen % 9);

                    t_info.tem_can_data = null;
                    unsafe
                    {
                        for (int i = 0; i < len; i++)
                        {
                            t_info.tem_can_data += "0x" + Tdata.VCI_CAN_OBJ1.Data[i].ToString("x2") + " ";
                        }
                    }

                    /* 当数据长度大于list指定的长度时,移除掉0号元素 */
                    if(tr_can_information.Count >= RT_MaxNumber)
                    {
                        tr_can_information.RemoveAt(0);
                    }

                    //if (tr_can_information.Count < 2)
                    //{
                        tr_can_information.Add(new RT_Frame_Info(rt_sequence_number++, T_timestamp, T_rt, t_info.tem_rt_ch,
                                            t_info.temp_can_id, t_info.tem_can_format, t_info.tem_can_type, len, t_info.tem_can_data));
                    //}
                    //else
                    //{
                    //    if (LastTimeStamp > ticks_ms)
                    //    {
                    //        tr_can_information.Insert(tr_can_information.Count - 2, new RT_Frame_Info(rt_sequence_number++, T_timestamp, T_rt, t_info.tem_rt_ch,
                    //                        t_info.temp_can_id, t_info.tem_can_format, t_info.tem_can_type, len, t_info.tem_can_data));
                    //    }
                    //    else
                    //    {
                    //        tr_can_information.Add(new RT_Frame_Info(rt_sequence_number++, T_timestamp, T_rt, t_info.tem_rt_ch,
                    //                        t_info.temp_can_id, t_info.tem_can_format, t_info.tem_can_type, len, t_info.tem_can_data));
                    //    }
                    //}

                Add_RT_DataToList_Flag = true;//标记收发数据已更新到List

                    //LastTimeStamp = ticks_ms;

                    //System.Diagnostics.Debug.WriteLine("时间戳:{0}(毫秒)", ticks_ms);  //总毫秒数
                }
            }
        }
        void setCAN_Praameter(VCI_INIT_CONFIG can_confi)
        {
            UInt32 val1 = VCI_InitCAN(m_devtype, m_devind, m_canind, ref can_confi);

            if (1 == val1)
            {
                CAN_Status = (ushort)(CAN_Status | (0x02));//标记设备已初始化 

                UInt32 val2 = VCI_ClearBuffer(m_devtype, m_devind, m_canind);

                if (1 == val2)
                {
                    UInt32 val3 = VCI_StartCAN(m_devtype, m_devind, m_canind);

                    if (1 == val3)
                    {
                        CAN_Status = (ushort)(CAN_Status | (0x04));//置打开通道标记
                        MainWindows_Output_Reminder("CAN" + m_canind.ToString() + "已开启");
                    }
                    else
                    {
                        CAN_Status = (ushort)(CAN_Status & (0x03));//清初打开通道标记
                        MainWindows_Output_Reminder("打开CAN" + m_canind.ToString() + "失败");
                    }
                }
                else
                {
                    MainWindows_Output_Reminder("清CAN" + m_canind.ToString() + "通道数据失败");
                }
            }
            else
            {
                CAN_Status = (ushort)(CAN_Status & (0x05));//清初始化标记
                MainWindows_Output_Reminder("初始化CAN" + m_canind.ToString() + "失败");
            }
        }
    
        ///


        /// 设置can参数窗口
        ///

        ///
        ///
        void updata_can_parameter(UInt32 can_ch, VCI_INIT_CONFIG can_config)
        {
            VCI_INIT_CONFIG config = new VCI_INIT_CONFIG();

            opendevice();//开启设备

            if (m_bOpen == 1)
            {
                m_canind = can_ch;
                config = can_config;

                CAN_Rate = (UInt16)config.Reserved;

                setCAN_Praameter(config);
            }
            else
            {
                MainWindows_Output_Reminder("设备未开启");
            }
        }
        ///


        /// CAN盒的接收线程,每隔5ms更新数据,并将数据添加到UDS缓存和原始数据缓存中
        ///

        private void rec_can_message_TH()
        {
            while(true)
            {
                UInt32 res = new UInt32();
                UInt32 i = 0;
                res = VCI_Receive(m_devtype, m_devind, m_canind, ref m_recobj[0],100,0);

                RT_CANDATA_INFO Tr_candata_info = new RT_CANDATA_INFO();

                if ((res > 0) && (res <= canbffersize))
                {
                    for (i = 0; i < res; i++)
                    {
                        if ((m_recobj[i].ID == Diag.Diag_CANparameters.Response_ID) && (Diag.Diag_CANparameters.Response_ID != 0x00))//uds报文
                        {
                            while (!(rec_uds_ringbuffer.ringbufferaddone(m_recobj[i])))//诊断报文必须接收
                            {
                                timeBeginPeriod(1);
                                Thread.Sleep(1);
                                timeEndPeriod(1);
                            }
                        }

                        /***将所有接收报文添加到缓存中****/
                        Tr_candata_info.RT_Index = (byte)0x5A;//标记此报文为接收报文
                        Tr_candata_info.VCI_CAN_OBJ1 = m_recobj[i];

                        if (false == (rt_can_ringbuffer.ringbufferputone2(Tr_candata_info)))//非诊断报文可以不接收
                        {
                            UInt16 j = 6;
                            bool val = false;

                            do
                            {
                                j--;
                                timeBeginPeriod(1);
                                Thread.Sleep(1);
                                timeEndPeriod(1);

                                val = rt_can_ringbuffer.ringbufferputone2(Tr_candata_info);                                
                            } while((val == false)&&(j>0));                            
                        }
                    }
                    r_sequence_number += res;//更新接收的帧数
                }
                else
                {
                    Is_RT_IDLE_Flag = true;
                }
                timeBeginPeriod(1);
                Thread.Sleep(1);//1ms    
                timeEndPeriod(1);
            }
        }
        ///


        /// 返回1,打开成功,其它失败
        ///

        ///
        private UInt32 opendevice()
        {
            UInt32 dwRel;

            dwRel = VCI_OpenDevice(m_devtype, m_devind, 0);
            if (dwRel == 1)
            {
                m_bOpen = 1;

                CAN_Status = (ushort)(CAN_Status | (0x01));//标记设备已开启 
                MainWindows_Output_Reminder("设备开启");
            }
            else if (dwRel == 0)
            {
                MainWindows_Output_Reminder("设备开启操作失败");
            }
            else
            {
                MainWindows_Output_Reminder("设备不存在或USB掉线");
            }

            return dwRel;
        }
        ///


        /// 打开设备 usbcan2 ,索引 0 
        ///

        ///
        ///
        private void 打开设备ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            opendevice();
        }
        ///
        /// 关闭设备,复位设备开启标志和初始化标志,关闭定时器timer_rec
        ///

        ///
        ///
        private void 关闭设备ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            UInt32 dwRel;
              
            dwRel = VCI_CloseDevice(m_devtype, m_devind); 

            if (dwRel == 1)
            {
                m_bOpen = 0;
                
                CAN_Status = (ushort)(CAN_Status & (0x06));//清设备已开启标记
                MainWindows_Output_Reminder("设备关闭");
            }
            else if (dwRel == 0)
            {
                MainWindows_Output_Reminder("设备关闭操作失败");
            }
            else
            {
                MainWindows_Output_Reminder("设备不存在或USB掉线");
            }
        }
        ///


        /// 退出应用程序之前,先关闭设备
        ///

        ///
        ///
        private void 退出设备ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (m_bOpen == 1)
            {
                VCI_CloseDevice(m_devtype, m_devind);
            }
            this.Close();
        }
        ///
        /// 应用程序关闭时,如果设备已打开,则关闭设备
        ///

        ///
        ///
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (m_bOpen == 1)
            {
                VCI_CloseDevice(m_devtype, m_devind);
            }
            timer1_dispaly_500ms.Enabled = false;


            /* 保存窗口参数 */
            if (File.Exists("Form1_Cfg.xml")) //如果文件存在,则删除对象
            {
                try
                {
                    File.Delete("Form1_Cfg.xml");
                }
                catch
                {

                }               
            }

            StreamWriter sr;

            string XMLString = "\r\n";

            XMLString += "\r\n";

            XMLString += "\t" + combobox_frame_type.SelectedIndex.ToString() + "\r\n"
                + "\t" + combobox_frame_format.SelectedIndex.ToString() + "\r\n"
                + "\t" + textBox_frame_iden.Text + "\r\n"
                + "\t" + textBox_frame_data.Text + "\r\n";

            XMLString += "\r\n";

            XMLString = AES.AesEncrypt(XMLString, "q1a2s3d4d5f6g7h8.");

            if(XMLString != "")
            {
                try
                {
                    sr = File.CreateText("Form1_Cfg.xml");
                    sr.WriteLine(XMLString);
                    sr.Close();
                }
                catch
                {

                }            
            }
            try
            {
                System.Environment.Exit(0);
            }
            catch
            {

            }
        }
        ///


        /// 发送一帧,数据内容在 VCI_CAN_OBJ
        ///

        ///
        ///
        ///
        ///
        ///
        /// 
        //private static long oldtime = 0;
        public static Boolean send_can_message(ref VCI_CAN_OBJ pSend)
        {

            //long nowtime = DateTime.Now.Ticks;
            //System.Diagnostics.Debug.WriteLine("VCI_Transmit()函数调用时间差,{0}(毫秒)", (nowtime - oldtime) / 10000);  获取当前时间
            //oldtime = nowtime;

            ///* 需要测试的代码 */
            uint t = VCI_Transmit(m_devtype, m_devind, m_canind, ref pSend, 1);
            //System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            //XCAN.watch.Stop();  //停止监视
            //TimeSpan timespan = watch.Elapsed;  //获取当前实例测量得出的总时间
            //System.Diagnostics.Debug.WriteLine("VCI_Transmit()发送时间:{0}(毫秒)", timespan.TotalMilliseconds);  //总毫秒数,发生时间:0.434(毫秒)

            //watch.Start();  //开始监视代码运行时间

            if ((t == 0)||(t > 1000))//发送一帧数据
            {
                t_error_number++;

                return false;//返回实际发送的帧数, =-1表示USB-CAN设备不存在或USB掉线
            }
            else
            {
                RT_CANDATA_INFO Tt_candata_info = new RT_CANDATA_INFO();

                Tt_candata_info.TimeStamp = DateTime.Now.Ticks;//获取当前时间
                Tt_candata_info.VCI_CAN_OBJ1 = pSend;
                Tt_candata_info.RT_Index = (byte)0xA5;//标记此报文为发送报文 

                //将此报文添加到收发buffer,若bufferyi满,则睡眠后再次尝试
                if (false == (rt_can_ringbuffer.ringbufferputone1(Tt_candata_info)))
                {
                    UInt16 j = 4;
                    bool addflag = false;

                    do
                    {
                        j--;
                        timeBeginPeriod(1);
                        Thread.Sleep(1);
                        timeEndPeriod(1);
                        addflag = rt_can_ringbuffer.ringbufferputone1(Tt_candata_info);

                    }while((addflag == false)&&(j>0));                                     
                }

                t_sequence_number++;//更新发送帧数
                return true;
            }          
        }

        ///


        /// 立即发送常规报文
        ///

        ///
        ///
        private void button_immediate_send_Click(object sender, EventArgs e)
        {
            if (m_bOpen == 0)//未开启
            {
                MainWindows_Output_Reminder("设备未开启");
                return;
            }

            VCI_CAN_OBJ sendobj = new VCI_CAN_OBJ();

            unsafe
            {
                try
                {                 
                    sendobj.RemoteFlag = (byte)combobox_frame_format.SelectedIndex;
                    sendobj.ExternFlag = (byte)combobox_frame_type.SelectedIndex;
                    sendobj.ID = System.Convert.ToUInt32("0x" + textBox_frame_iden.Text, 16);
                    if(0 == sendobj.ExternFlag)
                    {
                        if(sendobj.ID > 0x7ff)/* 标准帧ID范围 0 - 0x7FF */
                        {
                            MainWindows_Output_Reminder("ID超出范围");
                            return;
                        }
                    }
                    else
                    {
                        if (sendobj.ID > 0x1fffffff)/* 扩展帧ID范围 0 - 0x7FFFFFFF */
                        {
                            MainWindows_Output_Reminder("ID超出范围");
                            return;
                        }
                    }
                    int len = (textBox_frame_data.Text.Length + 1) / 3;
                    sendobj.DataLen = System.Convert.ToByte(len);
                    String strdata = textBox_frame_data.Text;
                    int i = -1;
                    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
                {
                    MainWindows_Output_Reminder("发送数据格式错误");
                    return;
                }
                bool returnvalue = send_can_message(ref sendobj);

                if (true == returnvalue)
                {
                    MainWindows_Output_Reminder("发送成功");
                }
                else
                {
                    MainWindows_Output_Reminder("发送失败");
                }
            }
        }

        ///


        /// 清接收,发送计数器,清List
        ///

        ///
        ///
        private void button_clear_data_Click(object sender, EventArgs e)
        {
            r_number = 0;
            t_number = 0;

            t_error_number = 0;
            r_sequence_number = 0;
            t_sequence_number = 0;
            rt_sequence_number = 0;//清空RT数据

            dataGridView1.RowCount = 0;

            tr_can_information.Clear();
            tr_can_information.TrimExcess();

            FristEnterRT_ticks = 0;

            label_rx.Text = "Rx:" + r_sequence_number.ToString();
            label_tx.Text = "Tx:" + t_sequence_number.ToString();
            label_Txerror.Text = "Tx_error:" + t_error_number.ToString();
        }
        ///


        /// 是否开启显示收发的数据
        ///

        ///
        ///
        private void button_display_on_off_Click(object sender, EventArgs e)
        {
            Is_RT_ButtonTurnOn = !Is_RT_ButtonTurnOn;//将按钮状态取反

            if (Is_RT_ButtonTurnOn)
            {                   
                button_display_on_off.BackgroundImage = Properties.Resources.stop; //是收发状态,显示暂停状态
            }
            else
            {                    
                button_display_on_off.BackgroundImage = Properties.Resources.play;//是暂停状态,显示收发状态
            }      
        }

        ///


        /// 诊断下载功能
        ///

        ///
        ///
        public static bool show_diag_form = false;
        private void 诊断测试ToolStripMenuItem_Click(object sender, EventArgs e)
        {           
            if (!Diag.isopen_diag)
            {
                Diag diag_form3 = new Diag();
                diag_form3.Show();
            }
            else
            {
                show_diag_form = true;
            }
        }

        ///


        /// 诊断发送函数,发送通道为 m_canind
        ///

        /// < VCI_CAN_OBJ类型 >
        ///
        public static Boolean g_uint8_CAN0SetTxStdMsg(ref VCI_CAN_OBJ pSend)
        {
            Boolean Tvalue =  send_can_message(ref pSend);
            return Tvalue;
        }

        ///


        /// 根据接收和发送标志,定时更新原始报文的显示,用于计算接收或发送的速度,帧/S
        ///

        ///
        ///
        long OldTimeValue = 0;
        private void timer_dispaly_500ms_Tick(object sender, EventArgs e)
        {
            long NewTimeValue = 0;
            long freq = 0;

            IsDisplayRate_Flag = !IsDisplayRate_Flag;

            if ((Is_RT_ButtonTurnOn) && (Add_RT_DataToList_Flag))
            {
                label_rx.Text = "Rx:" + r_sequence_number.ToString();
                label_tx.Text = "Tx:" + t_sequence_number.ToString();
                label_Txerror.Text = "Tx_error:" + t_error_number.ToString();

                dataGridView1.RowCount = tr_can_information.Count;

                if (Is_RT_IDLE_Flag)
                {
                    if (dataGridView1.Rows.Count > 0)//将光标指到最后一行数据,数据量大时,耗时较长
                    {
                        dataGridView1.FirstDisplayedScrollingRowIndex = dataGridView1.Rows[dataGridView1.Rows.Count - 1].Index;
                    }

                    Is_RT_IDLE_Flag = false;
                }

                Add_RT_DataToList_Flag = false;
            }

            if (true == IsDisplayRate_Flag)//一秒更新一次
            {                 
                QueryPerformanceCounter(ref NewTimeValue);
                QueryPerformanceFrequency(ref freq);

                long addtime = (NewTimeValue > OldTimeValue) ? (long)(((NewTimeValue - OldTimeValue) * 1000) / (double)(freq)) : 0;

                OldTimeValue = NewTimeValue;

                //System.Diagnostics.Debug.WriteLine("收发显示时间差,{0}(毫秒)", addtime);  //获取当前时间  

                float Tvalue1 = ((float)((t_sequence_number - t_number) * 1000)) / ((float)addtime);
                float Tvalue2 = ((float)((r_sequence_number - r_number) * 1000)) / ((float)addtime);

                label1_Trate.Text = String.Format("{0:F}", Tvalue1) + "帧/S";//默认为保留两位
                label1_Rrate.Text = String.Format("{0:F}", Tvalue2) + "帧/S";//默认为保留两位

                r_number = r_sequence_number;
                t_number = t_sequence_number;

                if((OldCAN_Status != CAN_Status) || (CAN_Rate != OldCAN_Rate))//更新CAN收发器状态
                {                   
                    OldCAN_Rate = CAN_Rate;
                    OldCAN_Status = CAN_Status;

                    if (0x07 == OldCAN_Status)
                    {
                        OldCAN_Rate = CAN_Rate;
                        this.Text = "XCAN" + "-CAN" + m_canind.ToString()+ "已开启" + "(" + OldCAN_Rate.ToString()+"K)";
                    }
                    else if(0x01 != (CAN_Status&0x01))
                    {
                        this.Text = "XCAN" + "-设备未开启";
                    }
                    else if (0x02 != (CAN_Status & 0x02))
                    {
                        this.Text = "XCAN" + "-设备未初始化";
                    }
                    else if (0x03 != (CAN_Status & 0x03))
                    {
                        this.Text = "XCAN" + "-通道未开启";
                    }
                    else
                    {
                        this.Text = "XCAN" + "-请重启软件";
                    }                   
                }
            }
            else
            {
                if(0 == VCI_ConnectDevice(m_devtype, m_devind))//每隔一秒检查设备连接状态
                {
                    CAN_Status = 0;
                    MainWindows_Output_Reminder("设备不存在或USB掉线");
                }
            }
        }
        ///


        /// 更新datagridview 
        ///

        ///
        ///
        private void dataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
        {
            try
            {
                switch (e.ColumnIndex)
                {
                    case 0:
                        e.Value = tr_can_information[e.RowIndex].序号;
                        break;
                    case 1:
                        e.Value = tr_can_information[e.RowIndex].时间戳;
                        break;
                    case 2:
                        e.Value = tr_can_information[e.RowIndex].传输方向;
                        break;
                    case 3:
                        e.Value = tr_can_information[e.RowIndex].传输通道;
                        break;
                    case 4:
                        e.Value = tr_can_information[e.RowIndex].帧ID;
                        break;
                    case 5:
                        e.Value = tr_can_information[e.RowIndex].帧格式;
                        break;
                    case 6:
                        e.Value = tr_can_information[e.RowIndex].帧类型;
                        break;
                    case 7:
                        e.Value = tr_can_information[e.RowIndex].数据长度;
                        break;
                    case 8:
                        e.Value = tr_can_information[e.RowIndex].帧数据;
                        break;
                    default:
                        ;
                        break;
                }
            }
            catch
            {

            }
        }
        ///


        /// 弹出一个设置窗口,用来初始化CAN0/CAN1通道
        ///

        ///
        ///
        /// 
        private void 开启ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!Set_Form.isopen_setcan)
            {
                Set_Form form2 = new Set_Form(updata_can_parameter);
                form2.Show();
            }
        }
        private void 设置ToolStripMenuItem1_Click(object sender, EventArgs e)
        {

        }

        private void 数据分析ToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void 帮助ToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        [DllImport("winmm")]
        static extern void timeBeginPeriod(int t);
        [DllImport("winmm")]
        static extern void timeEndPeriod(int t);
    }
}
 


       
   

你可能感兴趣的:(汽车电子)