/*
 * 由SharpDevelop创建。
 * 用户： meiyang
 * 日期: 2025/5/21
 * 时间: 9:39
 * 
 * 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
 */
using Microsoft.VisualBasic.ApplicationServices;
using PCIE_CAN;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.Xml.Linq;
using static PCIE_CAN.Sub_form;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Button;

namespace TJ_SangeElec
{
    public partial class PCIE_CAN : Form
    {
        Thread _canThread;
        bool _canRunFlag = false;
        public int RcvCan0 = 0;
        public int RcvCan1 = 0;
        public int SndCan0 = 0;
        public int SndCan1 = 0;
        public int DevType = -1;
        public int DevIndex = -1;
        public struct VCI_INIT_CONFIG
        {
            public byte FDFlag;
            public byte NON_ISO;
            public byte Timing0;
            public byte Timing1;
            public byte Mode;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
            public byte[] Reserved;
        }
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct VCI_CAN_OBJ
        {
            public uint ID;
            public byte RemoteFlag;
            public byte ExternFlag;
            public byte FDFlag;
            public byte DataLen;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public byte[] Data;
        }

        

        [DllImport("CANFD.dll", EntryPoint = "test_sum", CallingConvention = CallingConvention.Cdecl)]
        public static extern int test_sum(int a, int b);
        [DllImport("CANFD.dll", EntryPoint = "VCI_OpenDevice", CallingConvention = CallingConvention.Cdecl)]
        public static extern int VCI_OpenDevice(int Devtype, int DevIndex, int Reserved);
        [DllImport("CANFD.dll", EntryPoint = "VCI_CloseDevice", CallingConvention = CallingConvention.Cdecl)]
        public static extern int VCI_CloseDevice(int Devtype, int DevIndex);
        [DllImport("CANFD.dll", EntryPoint = "VCI_InitCan", CallingConvention = CallingConvention.Cdecl)]
        public static extern int VCI_InitCan(int DevType, int DevIndex, int CanIndex, VCI_INIT_CONFIG canInitConfig);
        [DllImport("CANFD.dll", EntryPoint = "VCI_GetReceiveNum", CallingConvention = CallingConvention.Cdecl)]
        public static extern int VCI_GetReceiveNum(int DevType, int DevIndex, int CanIndex);
        [DllImport("CANFD.dll", EntryPoint = "VCI_Receive", CallingConvention = CallingConvention.Cdecl)]
        public static extern int VCI_Receive(int DevType, int DevIndex, int CanIndex, ref VCI_CAN_OBJ pCanMsg, int WaitTime);
        [DllImport("CANFD.dll", EntryPoint = "VCI_Transmit", CallingConvention = CallingConvention.Cdecl)]
        public static extern int VCI_Transmit(int DevType, int DevIndex, int CanIndex, ref VCI_CAN_OBJ pCanMsg, int Count);
        [DllImport("CANFD.dll", EntryPoint = "VCI_SetValue", CallingConvention = CallingConvention.Cdecl)]
        public static extern int VCI_SetValue(int DevType, int DevIndex, int CanIndex, ref VCI_FILTER_CONFIG pFilterConfig);
        [DllImport("CANFD.dll", EntryPoint = "VCI_UpdateDev", CallingConvention = CallingConvention.Cdecl)]
        public static extern int VCI_UpdateDev(int DevType, int DevIndex, byte[] bin, UInt32 PackNum);
        public PCIE_CAN()
        {

            InitializeComponent();

            comboBox1.SelectedIndex = 0;
            comboBox2.SelectedIndex = 0;
            comboBox3.SelectedIndex = 0;
            comboBox4.SelectedIndex = 8;

            for (int i = 0; i < 50; i++)
            {
                dataGridView1.Rows.Add();
            }

            Console.WriteLine($"当前进程是64位: {Environment.Is64BitProcess}");
            Console.WriteLine($"当前操作系统是64位: {Environment.Is64BitOperatingSystem}");      

            _canThread = new Thread(canFrameRcv);
            _canThread.Start();

        }
        private readonly object _gridLock = new object();
        private void canFrameRcv(object obj)
        {
            VCI_CAN_OBJ canObj = new VCI_CAN_OBJ();
            canObj.Data = new byte[64];
            string channel = null;
            while (true)
            {
                if (!_canRunFlag)
                {
                    Thread.Sleep(10);
                    continue;
                }
                for (int i = 0; i < 2; i++)
                {
                    if (VCI_GetReceiveNum(0, 0, i) > 0)
                    {
                        VCI_Receive(0, 0, i, ref canObj, -1);
                        if (i == 0)
                        {
                            RcvCan0++;
                        }
                        else
                        {
                            RcvCan1++;
                        }
                        UpdateDataGridView(canObj, i);
                    }
                }
            }
        }



        private void UpdateDataGridView(VCI_CAN_OBJ canData, int channel)
        {
            if (dataGridView1.InvokeRequired)
            {
                // 结构体会被复制，数据安全
                dataGridView1.BeginInvoke(new Action<VCI_CAN_OBJ, int >(UpdateDataGridView), canData, channel);
                return;
            }

            lock (_gridLock)
            {
                int index = GetValidRowCount(dataGridView1);
                if (index + 1 >= dataGridView1.Rows.Count) dataGridView1.Rows.Add();
                dataGridView1.Rows[index].Cells[0].Value = index;
                dataGridView1.Rows[index].Cells[1].Value = channel == 0 ? "CAN0" : "CAN1";
                dataGridView1.Rows[index].Cells[2].Value = "Rx";
                dataGridView1.Rows[index].Cells[3].Value = DateTime.Now.ToString("MM/dd HH:mm:ss.fff");

                string id = "0x" + (canData.ID & 0x1FFFFFFFU).ToString("X");
                dataGridView1.Rows[index].Cells[4].Value = canData.FDFlag == 0 ? "CAN" : "FD";
                dataGridView1.Rows[index].Cells[5].Value = id;
                dataGridView1.Rows[index].Cells[6].Value = (canData.RemoteFlag == 0 ? "数据帧" : "远程帧");
                dataGridView1.Rows[index].Cells[7].Value = (canData.ExternFlag != 0 ? "扩展帧" : "标准帧");
                dataGridView1.Rows[index].Cells[8].Value = canData.DataLen;
                String data = null;
                for (int j = 0; j < canData.DataLen; j++)
                {
                    data += canData.Data[j].ToString("X2");
                    if (j < canData.DataLen - 1) data += " ";
                }
                dataGridView1.Rows[index].Cells[9].Value = data;

                toolStripStatusLabel6.Text = RcvCan0.ToString();
                toolStripStatusLabel10.Text = RcvCan1.ToString();
            }
        }






        private void toolStripButton_Click(object sender, EventArgs e)
        {
            ToolStripButton clicked = sender as ToolStripButton;
            if (clicked.Name == "toolStripButton5") //连接设备
            {
                int validRows = dataGridView1.RowCount;
                //MessageBox.Show("DataGridView 中包含数据行" + validRows);
                for (int i = validRows - 1; i >= 0; i--)
                {
                    dataGridView1.Rows.RemoveAt(i);
                }
                for (int i = 0; i < validRows; i++)
                {
                    dataGridView1.Rows.Add();
                }
                RcvCan0 = 0;
                RcvCan1 = 0;
                SndCan0 = 0;
                SndCan1 = 0;
                toolStripStatusLabel6.Text = RcvCan0.ToString();
                toolStripStatusLabel10.Text = RcvCan1.ToString();
                toolStripStatusLabel4.Text = SndCan0.ToString();
                toolStripStatusLabel8.Text = SndCan1.ToString();
            }

        }


        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            Sub_form sub = new Sub_form();
            if (sub.ShowDialog() == DialogResult.OK)
            {
                VCI_INIT_CONFIG initConfig = new VCI_INIT_CONFIG();
                
                DevType = sub.DevTpye;
                DevIndex = sub.DevIndex;
                if (VCI_OpenDevice(DevType, DevIndex, 0) == 0)
                {
                    MessageBox.Show("打开设备失败!");
                    return;
                }
                for (int i = 0; i < 2; i++)
                {
                    if (sub.can.ch[i].Enable == 1)
                    {
                        VCI_SetValue(DevType, DevIndex, i, ref sub.filter.ch[i]);

                        //Console.WriteLine("filter {0} {1}", sub.filter.ch[i].FilterIDEnable, sub.can.ch[i].Timing0);
                        initConfig.FDFlag = sub.can.ch[i].FDFlag;
                        initConfig.NON_ISO = sub.can.ch[i].NON_ISO;
                        initConfig.Timing0 = sub.can.ch[i].Timing0;
                        initConfig.Timing1 = sub.can.ch[i].Timing1;
                        initConfig.Mode = sub.can.ch[i].Mode;
                        int ret = VCI_InitCan(DevType, DevIndex, i, initConfig);
                        if (ret != 1)
                            MessageBox.Show("无法连接设备!");
                        else
                        {
                            _canRunFlag = true;
                            toolStripButton2.Enabled = true;
                            toolStripButton3.Enabled = true;
                            toolStripButton4.Enabled = true;
                            toolStripButton5.Enabled = true;
                            toolStripButton6.Enabled = true;
                            toolStripStatusLabel2.Text = "已连接";
                        }
                    }
                }
            }
        }



        int GetValidRowCount(DataGridView dgv)
        {
            int count = 0;
            foreach (DataGridViewRow row in dgv.Rows)
            {
                if (row.Cells[0].Value != null)
                {
                    count++;
                }
            }
            return count;
        }

        private void textBox4_TextChanged(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            VCI_CAN_OBJ CanObj = new VCI_CAN_OBJ();
            CanObj.Data = new byte[64];
            byte[] len = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64 };

            CanObj.ID = (UInt32)Convert.ToUInt32(textBox1.Text, 16);
            CanObj.RemoteFlag = (byte)comboBox3.SelectedIndex;
            CanObj.ExternFlag = (byte)comboBox2.SelectedIndex;
            CanObj.FDFlag = (byte)comboBox1.SelectedIndex;
            CanObj.DataLen = len[comboBox4.SelectedIndex];
            String[] data = textBox2.Text.Split(' ');
            int count = Convert.ToInt32(textBox3.Text);
            if (data.Length - 1 != CanObj.DataLen)
            {
                MessageBox.Show("数据长度错误");
                return;
            }  
            for (int i = 0; i < CanObj.DataLen; i++)
            {
                CanObj.Data[i] = Convert.ToByte(data[i]);
            }
            int CanIndex = radioButton1.Checked ? 0 : 1;
            if (CanIndex == 0)
                SndCan0++;
            else
                SndCan1++;
            for (int i = 0; i < count; i++)
            {
                int ret = VCI_Transmit(0, 0, CanIndex, ref CanObj, 1);
            }
            
            lock (_gridLock)
            {
                int index = GetValidRowCount(dataGridView1);
                if (index + 1 >= dataGridView1.Rows.Count) dataGridView1.Rows.Add();
                dataGridView1.Rows[index].Cells[0].Value = index;
                dataGridView1.Rows[index].Cells[1].Value = radioButton1.Checked ? "CAN0" : "CAN1";
                dataGridView1.Rows[index].Cells[2].Value = "Tx";
                dataGridView1.Rows[index].Cells[3].Value = DateTime.Now.ToString("MM/dd HH:mm:ss.fff");

                string id = "0x" + (CanObj.ID & 0x1FFFFFFFU).ToString("X");
                dataGridView1.Rows[index].Cells[4].Value = CanObj.FDFlag == 0 ? "CAN" : "FD";
                dataGridView1.Rows[index].Cells[5].Value = id;
                dataGridView1.Rows[index].Cells[6].Value = (CanObj.RemoteFlag == 0 ? "数据帧" : "远程帧");
                dataGridView1.Rows[index].Cells[7].Value = (CanObj.ExternFlag != 0 ? "扩展帧" : "标准帧");
                dataGridView1.Rows[index].Cells[8].Value = CanObj.DataLen;

                dataGridView1.Rows[index].Cells[9].Value = textBox2.Text;
                toolStripStatusLabel4.Text = SndCan0.ToString();
                toolStripStatusLabel8.Text = SndCan1.ToString();
            }
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            string[] items = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "12", "14", "16", "20", "32", "48", "64" };
            if (comboBox1.SelectedIndex == 0)
            {
                comboBox4.Items.Clear();
                for (int i = 0; i < 9; i++)
                {
                    comboBox4.Items.Add(items[i]);
                }
                comboBox4.SelectedIndex = 8;
            }
            else
            {
                comboBox4.Items.Clear();
                for (int i = 0; i < items.Length; i++)
                {
                    comboBox4.Items.Add(items[i]);
                }
                comboBox4.SelectedIndex = 8;
            }
        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            int ret = VCI_CloseDevice(DevType, DevIndex);
            if (ret == 1)
            {
                _canRunFlag = false;
                toolStripButton2.Enabled = false;
                toolStripButton3.Enabled = false;
                toolStripButton4.Enabled = false;
                toolStripButton5.Enabled = false;
                toolStripButton6.Enabled = false;
                toolStripStatusLabel2.Text = "未连接";
            }
        }


        private void 固件升级ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            byte[] buff = new byte[256];
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.InitialDirectory = Application.StartupPath;
            ofd.Filter = "*SG固件|*.bin";
            ofd.RestoreDirectory = true;
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                String fn = ofd.FileName;
                BinaryReader br = new BinaryReader(new FileStream(fn, FileMode.Open));
                long bins = br.BaseStream.Length;
                long binSize = br.BaseStream.Length;
                if (binSize % 256 != 0)  //增加为256整倍数
                {
                    binSize = (binSize / 256 + 1) * 256;
                }
                byte[] binBuf = new byte[binSize];  //保存固件
                for (long j = 0; j < br.BaseStream.Length; j++)
                {
                    binBuf[j] = br.ReadByte();
                }
                for (long j = br.BaseStream.Length; j < binSize; j++)
                {
                    binBuf[j] = 0xFF;  //补0xFF
                }
                br.Close();  //记得关闭字节流，不然一直占用
                progressBar_Update.Visible = true;
                progressBar_Update.Minimum = 0;
                progressBar_Update.Maximum = (int)(binSize / 256 - 1);
                progressBar_Update.Value = 0;
                progressBar_Update.Step = 1;

                uint packNum = 0;  //包序号

                while (packNum < binSize / 256)
                {
                    Console.WriteLine("升级 " + packNum + "  value"+progressBar_Update.Value);
                    progressBar_Update.PerformStep();
                    for (int j = 0; j < 256; j++)
                    {
                        buff[j] = binBuf[256 * packNum + j];
                    }
                    if (packNum == binSize / 256 - 1)  //最后一包了
                    {
                        packNum = 0xFFFFFFFF;
                    }
                    int ret = VCI_UpdateDev(DevType, DevIndex, buff, packNum);

  
                    if (packNum == 0xFFFFFFFF)
                    {
                        progressBar_Update.Visible = false;  //记得关掉显示
                        MessageBox.Show("固件升级成功", "SUCCERR");
                        return;
                    }
                    packNum += 1;  //发送下一包
                }
            }
            MessageBox.Show("固件异常", "ERROR");
        }
    }
}
