using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using cn.edu.suda.sumcu.iot;
using System.Runtime.InteropServices;

namespace RemoteUpdate
{
    public partial class frm_uartUpdate : Form
    {
        //定义使用的全局变量
        private frm_main fmain;  //主页面变量
        private Hex hex;  //Hex文件信息，整体更新用
        private Update update;  //更新类，保存更新所使用的帧结构体与方法
        private SynchronizationContext m_SyncContext = null;    //用于安全地跨线程访问控件
        public EMUART emuart;     //串口通信类对象
        private uint softVersion; //保存终端更新程序版本，0表示更新版本不详，1表示更新版本为VA.10之前，2表示更新版本为VA.10之后
        private Hex_old hex_old;  //（VA.10版本之前）更新程序Hex对象
        private Update_old update_old;  //（VA.10版本之前）更新类对象，保存更新所使用的帧结构体与方法
        //握手帧
        // LayoutKind.Sequential用于强制将成员按其出现的顺序进行顺序布局,字符串转换成ANSI字符串，Pack表示1字节对齐
        [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct shakeData
        {
            // SizeConst用来定义数组大小
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 25)]
            public byte[] uecomType;          //通信模组类型
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
            public byte[] mcuType;            //MCU类型
            public uint uStartAds;            //User程序起始地址
            public uint uCodeSize;            //User程序总代码大小
            public uint replaceNum;           //替换更新最大字节
            public uint reserveNum;           //保留更新最大字节（不等于0意味着有User程序）
        }
        private shakeData shakedata; 
        private string uecomType;   //通信模组类型
        private string mcuType;     //MCU类型
        private uint uStartAds;     //User程序起始地址
        private uint uCodeSize;     //User程序总代码大小
        private uint replaceNum;    //替换更新最大字节
        private uint reserveNum;    //保留更新最大字节（不等于0意味着有User程序）
        private byte overallStyle;  //整体更新方式

        //======================================================================
        //函数名称：frm_uartUpdate
        //函数返回：frm_uartUpdate窗体构造函数
        //参数说明：无
        //功能概要：完成frm_uartUpdate窗体的初始化工作
        //======================================================================
        public frm_uartUpdate()
        {
            InitializeComponent();
        }

        //======================================================================
        //函数名称：frm_uartUpdate_Load
        //函数返回：无
        //参数说明：无
        //功能概要：窗体加载事件，窗体加载时自动调用
        //======================================================================
        private void frm_uartUpdate_Load(object sender, EventArgs e)
        {
            //（1）本窗体由frmMain创建，所以本窗体的父窗体为frmMain
            fmain = (frm_main)this.MdiParent;  //得到frmMain窗体变量
            m_SyncContext = SynchronizationContext.Current;   //用于安全地跨线程访问控件
            overallStyle = 0;    //更新方式为默认为整体更新方式
            //（2）初始化Hex变量
            hex = new Hex();
            //（3）初始化串口
            emuart = new EMUART();
            //（4）初始化版本号
            softVersion = 0;  //表示版本号不明
            //（5）初始化原更新程序变量           
            hex_old = new Hex_old();

        }

        //======================================================================
        //函数名称：btn_uartcheck_Click
        //函数返回：无
        //参数说明：无
        //功能概要：“连接GEC”按钮点击事件，重新连接终端
        //======================================================================
        private void btn_uartcheck_Click(object sender, EventArgs e)
        {
            //（1）变量声明
            int ret;            //返回值
            string com = "";    //串口信息
            string sTemp = "";
            byte[] recv = null;//保存串口接收信息
            byte[] shake = { (byte)10, (byte)'s', (byte)'h', (byte)'a', (byte)'k', (byte)'e' }; //与终端握手帧数据

            //（2）清除一些可能余留信息
            this.lbl_uartstate.Text = "";       //右上角显示区
            fmain.lbl_mainstatus.Text = "运行状态：正在连接GEC...";     //底部提示
            this.lst_codeshow1.Items.Clear();   //左侧代码显示区
            this.txt_updateinfo1.Text = "";     //右侧更新提示区
            this.Refresh();                     //刷新显示 
            btn_uartcheck.Text = "重新连接GEC"; //更改显示文字            

            //（3）重新遍历串口，寻找终端
            if (emuart._Uartport != null) emuart._Uartport.Close();
            Thread.Sleep(10);   //等待串口关闭
            emuart.RawDataReceivedEvent -= new EMUART.RawDataReceived(DataRecv);//解除事件绑定的方法，加快握手速度
            emuart = new EMUART();    //每次“重新连接”重新实例化
            fmain.lbl_mainstatus.Text = "运行状态：正在连接GEC...正在查找匹配设备...";     //底部提示
            ret = emuart.findDevice(out com, 115200);  //寻找emuart设备
            this.lbl_uartstate.Text = com;       //右上角显示区
            fmain.lbl_mainstatus.Text = "运行状态：正在连接GEC...尝试与匹配设备建立通信...";     //底部提示

            //（4）根据寻找串口的返回值确定执行下列分支
            //（4.1）如果连接终端的emuart失败，退出函数
            if (ret == 1) goto btn_uartcheck_Click_EXIT1;
            //（4.2）找到串口，没有找到UE，退出函数
            else if (ret == 2) goto btn_uartcheck_Click_EXIT2;
            //（4.3)如果找到串口与UE,向设备发送握手帧
            fmain.lbl_mainstatus.Text = "运行状态：正在连接GEC...向该设备发送握手信息，准备接收设备返回消息...";     //底部提示
            emuart.bufferClear();   //清除接收数组缓冲区
            emuart.send(shake, out recv, 200, 3); //获得设备的信息在recv中
            this.btn_fileopen1.Enabled = true;     //允许选择文件功能
            fmain.lbl_mainstatus.Text = "运行状态：正在连接GEC...正在处理设备返回信息...";     //底部提示
            if (recv == null) goto btn_uartcheck_Click_EXIT3;//未收到数据，退出              
            //（4.4)发送握手帧后，若收到设备返回数据，处理之
            //（4.4.1）如果终端的更新程序版本为VA.10以后的版本（通用于所有GEC芯片）
            if (recv.Length == Marshal.SizeOf(typeof(shakeData)))
            {
                fmain.lbl_mainstatus.Text = "运行状态：成功连接到GEC设备";     //底部提示
                softVersion = 2;  //表示终端更新程序为A.10之后的通用版本
                //byte数组转结构体
                shakedata = (shakeData)bytesToStruct(recv, typeof(shakeData));
                //获取握手帧数据
                uecomType = Encoding.Default.GetString(shakedata.uecomType).Replace("\0", "");
                mcuType = Encoding.Default.GetString(shakedata.mcuType).Replace("\0", "");
                uStartAds = shakedata.uStartAds;
                uCodeSize = shakedata.uCodeSize;
                replaceNum = shakedata.replaceNum;
                reserveNum = shakedata.reserveNum;
                //设置设备信息                   
                sTemp = com + "：" + uecomType + " " + mcuType;  //设备信息
                //状态提示
                this.lbl_uartstate.Text = sTemp;     //右上角显示区
                fmain.lbl_mainstatus.Text = "运行状态：" + sTemp;   //底部提示
                fmain.lbl_protocal.Text = "协议：串口";    //底部中间协议类型
                fmain.lbl_protocalinfo.Text = "协议信息：端口" + com + ",波特率115200";   //底部右侧协议信息
                this.txt_updateinfo1.Text = sTemp + "\r\n";     //右侧更新提示区     
                //若保留更新最大字节为0表示目前没有User程序，此时只能进行整体更新
                if (reserveNum == 0)
                {
                    txtShow1("可进行GEC中User程序更新\r\n");     //右侧更新提示区  
                }
                //如果存在串口，则允许接收调试信息
                if (fmain.mfrm_uartUpdate.emuart.haveUE)
                {
                    //绑定串口结束事件，处理串口调试信息
                    emuart.RawDataReceivedEvent += new EMUART.RawDataReceived(DataRecv);
                    fmain.lbl_mainstatus.Text = "过程提示:串口接收界面开启成功";   //底部提示
                }
            }
            //（4.4.2）如果终端的更新程序版本为VA.10及其以前的版本
            else if (System.Text.Encoding.Default.GetString(recv).Contains("shake:GEC-"))
            {
                softVersion = 1;   //表示终端更新程序为A.10及之前的版本
                sTemp = "MKL36Z64" + "(" + com + ")";//设备信息
                this.lbl_uartstate.Text = "成功连接" + sTemp;       //右上角显示区
                fmain.lbl_mainstatus.Text = "运行状态：正在连接GEC...成功连接" + sTemp;   //底部提示
                this.lbl_uartstate.Text = "找到终端设备" + sTemp;   //右上角显示区
                fmain.lbl_protocal.Text = "协议：串口";    //底部中间协议类型
                fmain.lbl_protocalinfo.Text = "协议信息：端口" + com + ",波特率115200";   //底部右侧协议信息
                //如果存在串口，则允许接收调试信息
                if (fmain.mfrm_uartUpdate.emuart.haveUE)
                {
                    //绑定串口结束事件，处理串口调试信息
                    emuart.RawDataReceivedEvent += new cn.edu.suda.sumcu.iot.EMUART.RawDataReceived(DataRecv);
                    fmain.lbl_mainstatus.Text = "过程提示:串口接收界面开启成功";   //底部提示
                }
            }
            //（4.4.3）若收到错误返回信息，退出函数
            else goto btn_uartcheck_Click_EXIT3;          
                         
         //(5)退出区
        //(5.1)退出函数
         btn_uartcheck_Click_EXIT:    
            return;

        //(5.2)不存在可用串口
         btn_uartcheck_Click_EXIT1:    
            this.btn_autoupdate1.Enabled = false;    //禁止串口更新操作
            this.btn_fileopen1.Enabled = false;      //禁止选择文件功能
            this.lbl_uartstate.Text = "当前不存在可用串口";       //右上角显示区
            fmain.lbl_mainstatus.Text = "运行状态：当前不存在可用串口";   //底部提示
            fmain.lbl_protocal.Text = "协议：";    //底部中间协议类型
            fmain.lbl_protocalinfo.Text = "协议信息："; //底部右侧协议信息
            this.txt_updateinfo1.Text = "没有找到USB串口，可能原因如下：\r\n（1）USB串口未插上PC\r\n（2）PC未安装串口驱动\r\n";     //右侧更新提示区
            goto btn_uartcheck_Click_EXIT;

        //(5.3)存在串口，但不存在emuar设备
        btn_uartcheck_Click_EXIT2:
            emuart.terminate(115200); //发送数据给终端设备，让终端设备清空其数据缓冲区
            this.lbl_uartstate.Text = "已连接串口" + com + "但未找到设备";       //右上角显示区
            fmain.lbl_mainstatus.Text = "运行状态：已连接串口" + com + "但未找到设备";   //底部提示
            fmain.lbl_protocal.Text = "协议：";   //底部中间协议类型
            fmain.lbl_protocalinfo.Text = "协议信息：";    //底部右侧协议信息
            fmain.lbl_mainstatus.Text = "运行状态：与设备建立连接失败，请尝试重新连接设备";   //底部提示
            //右侧更新提示区
            this.txt_updateinfo1.Text = "有USB串口，但未连上终端，可能原因如下：\r\n（1）USB串口驱动需更新\r\n（2）USB串口未连接终端\r\n（3）终端程序未运行\r\n";
            goto btn_uartcheck_Click_EXIT;

        //(5.4)未收到返回信息或收到错误返回信息
        btn_uartcheck_Click_EXIT3:
            emuart.terminate(115200); //发送数据给终端设备，让终端设备清空其数据缓冲区
            fmain.lbl_mainstatus.Text = "运行状态：正在连接GEC...未收到返回信息";     //底部提示
            this.lbl_uartstate.Text = "找到GEC在" + com + "但握手失败，请再次单击[重新连接]按钮";  //右上角显示
            goto btn_uartcheck_Click_EXIT;
     
        }

        //======================================================================
        //函数名称：btn_fileOpen1_Click
        //函数返回：无
        //参数说明：无
        //功能概要：导入待整体更新Hex文件并对该文件进行解析取出其有效数据
        //======================================================================
        private void btn_fileopen1_Click(object sender, EventArgs e)
        {
            //（1）变量声明           
            int flag;
            uint startAdd;            //代码起始地址
            uint codesize;            //代码大小
            string filePath;          //文件路径
            string fileName;          //文件名
            string line;              //Hex文件行数据
            List<hexStruct_old> list; //更新程序对应Hex文件保存变量            
            //（2）如果终端更新程序版本为VA.10之后的版本
            if (softVersion == 2)
            {
                //（2.1）导入Hex文件
                OpenFileDialog ofd = new OpenFileDialog();  //打开文件对话框
                ofd.Filter = "hex file(*.hex)|*.hex";
                ofd.ShowDialog();
                //（2.2）获取文件名
                filePath = ofd.FileName;
                //（2.3）导入解析Hex文件
                flag = hex.loadFile(filePath);
                if (flag != 0) goto btn_fileopen1_Click_EXIT1;               
                //（2.4）获取导入的文件信息
                fileName = hex.getFileName();
                startAdd = hex.getStartAddress();
                codesize = hex.getCodeSize();
                //（2.5）判断导入的Hex文件首地址是否正确
                if (startAdd != uStartAds) goto btn_fileopen1_Click_EXIT3;//地址不符合               
                //（2.6）状态提示
                this.lbl_filename1.Text = fileName;
                this.prg_update1.Value = 0;
                this.lbl_progressbar1.Text = "";
                this.btn_autoupdate1.Enabled = true;  //允许整体更新功能
                txtShow1("导入" + fileName + "文件成功！\r\n");     //右侧更新提示区  
                this.lst_codeshow1.Items.Clear();    //左侧代码显示区
                foreach (string str in hex.getHexStrList())
                {
                    this.lst_codeshow1.Items.Add(str);    //左侧代码显示区
                }
                fmain.lbl_mainstatus.Text = "运行状态：" + fileName + "文件选择成功，文件数据解析成功";   //底部提示
            }
            //（3）如果终端更新程序版本为VA.10及其之前的版本
            else if (softVersion == 1)
            {
                //（3.1）导入Hex文件
                OpenFileDialog ofd = new OpenFileDialog();  //打开文件对话框
                ofd.Filter = "hex file(*.hex)|*.hex";
                ofd.ShowDialog();
                //（3.2）获取文件名
                filePath = ofd.FileName;
                fileName = filePath.Substring(filePath.LastIndexOf("\\") + 1);//最后一个\\后是文件名
                if (fileName == "")  goto btn_fileopen1_Click_EXIT2;//未选择Hex文件
                fmain.lbl_mainstatus.Text = "运行状态：" + fileName + "文件导入成功";   //底部提示
                //（3.3）获取文件数据，并显示在文件显示框
                FileStream fs = new FileStream(filePath, FileMode.Open);
                if (fs == null) goto btn_fileopen1_Click_EXIT1;    //文件打开失败
                fmain.lbl_mainstatus.Text = "运行状态：" + fileName + "文件打开成功，正在读取文件数据...";   //底部提示
                //（3.4）读取数据
                StreamReader sr = new StreamReader(fs);  //读取数据流
                hex_old.clear();  //先清空hex数据，准备接收hex数据
                this.lst_codeshow1.Items.Clear();    //左侧代码显示区
                //（3.5）遍历hex文件，读出到文本框中
                while (true)
                {
                    line = sr.ReadLine();  //读取1行数据
                    if (line == null) break;  //文件读取错误，退出
                    hex_old.addLine(line);  //获取hex文件行数据有效数据
                    this.lst_codeshow1.Items.Add(line);     //左侧代码显示区                  
                }
                sr.Close();  //关闭数据流
                fs.Close();             
                list = hex_old.getHexList();
                //（3.6）判断读取文件的合法性,如果不合法
                if (list[0].address != 0x6800) goto btn_fileopen1_Click_EXIT3;
                //（3.7）判断读取文件的合法性,如果合法               
                this.lbl_filename1.Text = fileName;
                this.prg_update1.Value = 0;
                this.lbl_progressbar1.Text = "";
                this.btn_autoupdate1.Enabled = true;   //允许整体更新功能
                txtShow1("导入" + fileName + "文件成功！\r\n");   //右侧更新提示区  
                fmain.lbl_mainstatus.Text = "运行状态：" + fileName + "文件选择成功，文件数据解析成功";   //底部提示             
            }

        //（4）退出区
        //（4.1）退出函数
        btn_fileopen1_Click_EXIT:  
            return;

        //（4.2）导入hex文件失败
        btn_fileopen1_Click_EXIT1: 
            this.btn_autoupdate1.Enabled = false;  //禁止整体更新功能
            fmain.lbl_mainstatus.Text = "运行状态：请重新选择文件";   //底部提示
            MessageBox.Show("Hex文件异常!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Stop);
            goto btn_fileopen1_Click_EXIT;

        //（4.3）未选择Hex文件
        btn_fileopen1_Click_EXIT2:
            fmain.lbl_mainstatus.Text = "运行状态：未选择Hex文件";   //底部提示
            goto btn_fileopen1_Click_EXIT;

        //（4.4）导入的Hex文件不合法
        btn_fileopen1_Click_EXIT3:
            fmain.lbl_mainstatus.Text = "运行状态：请重新选择文件";   //底部提示
            MessageBox.Show("Hex文件异常!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Stop);
            txtShow1("导入的" + fileName + "文件首地址不合法，请检查！\r\n");     //右侧更新提示区  
            this.btn_autoupdate1.Enabled = false;  //不允许整体更新功能
            fmain.lbl_mainstatus.Text = "运行状态：" + fileName + "文件首地址不合法，请检查！";   //底部提示
            goto btn_fileopen1_Click_EXIT;

        }

        //======================================================================
        //函数名称：btn_autoUpdate1_Click
        //函数返回：无
        //参数说明：无
        //功能概要：“一键自动更新”（整体更新）按钮点击事件，进行程序更新操作
        //======================================================================
        private void btn_autoupdate1_Click(object sender, EventArgs e)
        {
            //（1）变量声明
            int sum;          //发送总帧数
            int cur;          //当前发送帧号
            byte[] senddata = null;
            byte[] recvdata = null;
            int flag;         //（VA.10之前）更新标志位
            byte[] shake = { (byte)10, (byte)'s', (byte)'h', (byte)'a', (byte)'k', (byte)'e' };  //握手帧
            byte[] startUpdate = { (byte)11, (byte)'u', (byte)'p', (byte)'d', (byte)'a', (byte)'t', (byte)'e' }; //开始更新提示帧
            byte[] zero = new byte[500];
            byte[] bRet = null;
            byte[] data = null;
            byte[] reStartFrame = new byte[3];

            //（2）如果更新程序版本为VA.10之后的版本
            if (softVersion == 2)
            {
                //（2.1）若未导入Hex文件或串口连接失败则退出（防错用）
                if (hex.getHexList().Count == 0) goto btn_autoupdate1_Click_EXIT1;//未导入Hex文件
                if (emuart == null || emuart.haveUE == false) goto btn_autoupdate1_Click_EXIT2;//串口连接失败
                //（2.2）开始更新
                update = new Update(overallStyle, hex.getHexList());  //update初始化
                sum = update.getFrameNum();
                try
                {
                    fmain.lbl_mainstatus.Text = "运行状态：整体更新开始";   //底部提示
                    txtShow1("运行状态：整体更新开始\r\n");     //右侧更新提示区  
                    //（2.2.1）从update类中取出待发送的数据帧，逐一进行发送
                    while ((senddata = update.getNextFrame()) != null)
                    {
                        cur = update.getNextIndex();
                        //非最后的更新命令帧，需返回数据
                        if (cur != sum - 1)  
                        {
                            //第26帧做特殊处理，防止延迟
                            if (cur == 25)
                            {
                                int aaa = 10;
                            }
                            if (!emuart.send(senddata, out recvdata, 500, 2)) goto btn_autoupdate1_Click_EXIT5;  //未接收到正确返回信息
                            if (update.updateRecv(recvdata) != 0) goto btn_autoupdate1_Click_EXIT6;  //更新返回帧异常
                            //当前帧数据操作成功，进度条显示更新进度
                            this.prg_update1.Value = (cur + 1) * 100 / sum;            //进度条显示
                            this.lbl_progressbar1.Text = (cur + 1) * 100 / sum + "%";  //进度百分比显示
                            this.prg_update1.Refresh();
                            //成功提示
                            txtShow1("当前第" + (cur + 1).ToString() + "/" + sum.ToString() + "帧 \r\n");     //右侧更新提示区  
                        }
                        //最后一帧更新命令帧，仅需发送
                        else  
                        {
                            emuart.send(senddata, out recvdata, 300, 2);
                            txtShow1("当前第" + (cur + 1).ToString() + "/" + sum.ToString() + "帧 \r\n");     //右侧更新提示区  
                        }
                    }
                    //（2.3）更新成功 
                    goto btn_autoupdate1_Click_EXIT3;
                }
                catch (Exception ex)
                {
                    fmain.lbl_mainstatus.Text = "运行状态：系统异常退出";   //底部提示
                    txtShow1("系统异常退出\r\n" + ex + "\r\n");     //右侧更新提示区  
                    goto btn_autoupdate1_Click_EXIT;
                }
            }
            //（3）如果更新程序版本为VA.10及其之前的版本
            else if (softVersion == 1)
            {
                //（3.1）若未导入Hex文件或串口连接失败则退出（防错用）
                flag = 0;
                if (hex_old.getHexList() == null) goto btn_autoupdate1_Click_EXIT1;    //未导入Hex文件
                if (emuart == null || emuart.haveUE == false) goto btn_autoupdate1_Click_EXIT2;    //串口连接失败
                //（3.2）显示区初始化
                fmain.lbl_mainstatus.Text = "";   //左下提示区
                txtShow1("");     //右侧更新提示区  
                //（3.3）Hex文件选择成功、串口选择成功则进行自动更新操作//右下提示区
                update_old = new Update_old(hex_old.getHexList());    //新的更新数据列表
                try
                {                 
                    //（3.3.1）通过串口向MCU发送开始更新提示startUpdate,即11, update;
                    if (!(emuart.send(startUpdate, out bRet, 300, 2) && bRet != null
                        && Encoding.Default.GetString(bRet) == "Start Update")) goto btn_autoUpdate1_Click_EXIT8;
                    fmain.lbl_mainstatus.Text = "运行状态：收到UE握手信息，将开始程序更新操作...";      //底部提示
                    txtShow1("运行状态：收到UE握手信息，将开始程序更新操作...\r\n");                    //右侧更新提示区  
                    //（3.3.2）更新操作初始化
                    sum = update_old.getFrameNum();      //sum←待发送的总帧数
                    reStartFrame[0] = 0x04;          //返回帧的帧头reStartFrame[0]←0x04
                    //（3.3.3）发送第一帧数据，需等待较长时间
                    for (int i = update_old.getCurCount(); i < sum; i++)
                    {
                        data = update_old.getNextFrame();    //data←一帧数据
                        if (i == 0) { Array.Copy(data, 1, reStartFrame, 1, 2); }; // 若是第0帧data变动
                        //第26帧做特殊处理，防止延迟
                        if (i == 26)
                        {
                            int aaa = 10;
                        }
                        //发送数据，并等待接收返回信息
                        //(几种错误情况)
                        if (!emuart.send(data, out bRet, 500, 2)) goto btn_autoUpdate1_Click_EXIT9;   //未正确返回信息
                        if (bRet[0] == (byte)2 && bRet[1] != 0) goto   btn_autoUpdate1_Click_EXIT10;  //UE接收数据帧出错
                        if ((bRet[0] == 1) && ((int)bRet[2] * 256 + bRet[1] != i)) goto btn_autoUpdate1_Click_EXIT11;  //UE接收到的帧数有误
                        //（正确情况）进度条显示更新进度                      
                        this.prg_update1.Value = update_old.getSendCount() * 100 / sum;     //进度条显示       
                        this.lbl_progressbar1.Text = update_old.getSendCount() * 100 / sum + "%";//进度条百分比显示 
                        this.lbl_progressbar1.Refresh();
                        //成功提示
                        txtShow1("当前第" + (i + 1).ToString() + "/" + sum.ToString() + "帧  " + bRet[0].ToString() + "\r\n");     //右侧更新提示区  

                    }
                    //（3.4）程序更新成功
                    goto btn_autoupdate1_Click_EXIT4;
                }
                catch (Exception ex)
                {
                    fmain.lbl_mainstatus.Text = "运行状态：系统异常退出" + ex;   //底部提示
                    txtShow1("系统异常退出\r\n" + ex);     //右侧更新提示区  
                    goto btn_autoUpdate1_Click_EXIT7;
                }
            }



        //（4）退出区
        //（4.1）退出函数
        btn_autoupdate1_Click_EXIT:
            return;

        //（4.2）Hex文件未选择
        btn_autoupdate1_Click_EXIT1:
            fmain.lbl_mainstatus.Text = "运行状态：Hex文件未选择";   //底部提示
            goto btn_autoupdate1_Click_EXIT;

            //（4.3）未连接设备
        btn_autoupdate1_Click_EXIT2:
            fmain.lbl_mainstatus.Text = "运行状态：未连接设备，请点击“重新连接”";   //底部提示
            goto btn_autoupdate1_Click_EXIT;

            //（4.4）程序整体更新成功
        btn_autoupdate1_Click_EXIT3:
            fmain.lbl_mainstatus.Text = "运行状态：程序整体更新成功";   //底部提示
            txtShow1("程序整体更新成功\r\n");     //右侧更新提示区  
            this.prg_update1.Value = 100;
            this.lbl_progressbar1.Text = "100%";
            this.lbl_progressbar1.Refresh();
            goto btn_autoupdate1_Click_EXIT;

            //（4.5）（VA.10之前）程序更新成功
        btn_autoupdate1_Click_EXIT4:
            fmain.lbl_mainstatus.Text = "运行状态：程序更新成功";   //底部提示
            txtShow1("程序更新成功！\r\n");     //右侧更新提示区  
            this.prg_update1.Value = 100;
            goto btn_autoUpdate1_Click_EXIT7;

         //（4.6）未接收到终端返回数据
        btn_autoupdate1_Click_EXIT5:
            txtShow1("错误提示：未接收到终端返回数据\r\n");     //右侧更新提示区  
            goto btn_autoupdate1_Click_EXIT;

         //（4.7）接收到的更新返回数据异常
        btn_autoupdate1_Click_EXIT6:
            txtShow1("错误提示：接收到的更新返回数据异常\r\n");     //右侧更新提示区  
            goto btn_autoupdate1_Click_EXIT;

        //（4.8）（VA.10之前）程序更新操作结束，重新允许导入新的Hex文件、切换更新方式、重连串口等操作
        btn_autoUpdate1_Click_EXIT7:          
            this.btn_fileopen1.Enabled = true;
            if (flag != 1) this.btn_autoupdate1.Enabled = true;   
            System.Threading.Thread.Sleep(100);
            return;

        //以下都是VA.10版本之前的更新错误处理
        //（4.9）与UE握手失败
        btn_autoUpdate1_Click_EXIT8:
            txtShow1("错误提示1：与UE握手失败！\r\n");     //右侧更新提示区  
            flag = 1;    //更新失败
            goto btn_autoUpdate1_Click_EXIT7;

        //（4.10）更新过程未收到返回信息
        btn_autoUpdate1_Click_EXIT9:
            txtShow1("错误提示2：更新过程未收到返回信息！\r\n");     //右侧更新提示区  
            flag = 1;    //更新失败
            goto btn_autoUpdate1_Click_EXIT7;

        //（4.11）UE告知接收数据帧有误
        btn_autoUpdate1_Click_EXIT10:
            txtShow1("错误提示3：UE告知接收数据帧有误！\r\n");     //右侧更新提示区  
            flag = 1;    //更新失败
            goto btn_autoUpdate1_Click_EXIT7;

        //（4.12）UE返回的帧数不对
        btn_autoUpdate1_Click_EXIT11:
            txtShow1("错误提示4：UE返回的帧数不对！(" + ((int)bRet[2] * 256 + bRet[1]).ToString() + ")\r\n");//右侧更新提示区
            flag = 1;    //更新失败
            goto btn_autoUpdate1_Click_EXIT7;

        }

      
        //======================================================================
        //函数名称：txtShow1
        //函数返回：无
        //参数说明：str:在终端执行信息提示框追加显示的内容
        //功能概要：整体更新过程中，在终端执行信息提示框txt_uartinfo1中追加提示
        //          信息，并显示最新信息      
        //======================================================================
        private void txtShow1(string str)
        {            
            //右侧更新提示区
            if (this.txt_updateinfo1.Lines.Length >= 55) this.txt_updateinfo1.Text = String.Empty; //长度过长则清空内容
            this.txt_updateinfo1.Text += str;
            this.txt_updateinfo1.Refresh();
            this.txt_updateinfo1.SelectionStart = this.txt_updateinfo1.Text.Length;  //光标指向最后一位
            this.txt_updateinfo1.ScrollToCaret();   //移动到光标处
            
        }
     
        //======================================================================
        //函数名称：bytesToStruct
        //函数返回：byte数组转换为对应的结构体
        //参数说明：bytes:字节数组;type:结构体类型
        //功能概要：将byte字节数组数据转换为对应的结构体数据
        //======================================================================
        private object bytesToStruct(byte[] bytes, Type type)
        {
            //（1）变量声明
            int size;
            object obj;
            IntPtr structPtr;

            size = Marshal.SizeOf(type);
            //（2）判断字节长度
            if (size > bytes.Length) return null;
            //（3）分配结构体内存空间
            structPtr = Marshal.AllocHGlobal(size);
            //（4）将byte数组拷贝到分配好的内存空间
            Marshal.Copy(bytes, 0, structPtr, size);
            //（5）将内存空间转换为目标结构体
            obj = Marshal.PtrToStructure(structPtr, type);
            //（6）释放内存空间
            Marshal.FreeHGlobal(structPtr);

            return obj;
        }

        //======================================================================
        //函数名称：SetTextSafePost
        //函数返回：无
        //参数说明：data:待显示数据的二进制形式
        //功能概要：将接收到的调试数据显示到文本控件上的异步操作
        //======================================================================
        private void SetTextSafePost(object data)
        {
            //显示调试信息
            if (infor_dispaly_button.Text == "暂停")
                txtShow1(Encoding.Default.GetString((byte[])data)); //右侧更新提示区
        }


        //======================================================================
        //函数名称：DataRecv
        //函数返回：无
        //参数说明：data:待显示数据的二进制形式
        //功能概要：执行异步操作，将接收到的调试数据显示到文本控件上
        //======================================================================
        private void DataRecv(byte[] data)
        {
            m_SyncContext.Post(SetTextSafePost, data);
        }

        //======================================================================
        //函数名称：
        //函数返回：无
        //参数说明：data:待显示数据的二进制形式
        //功能概要：执行异步操作，将接收到的调试数据显示到文本控件上
        //20190306
        //======================================================================
        private void infor_dispaly_button_Click(object sender, EventArgs e)
        {
            if (infor_dispaly_button.Text == "暂停")

                infor_dispaly_button.Text = "继续";
            else
                infor_dispaly_button.Text = "暂停";
        }
    }
}


