using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace SerialPort
{
    ///---------------------------------------------------------------------*
    ///Timer　 :Timer演示　　　                                             *
    ///功能描述:测试Timer串口通信是否正常　                                 *
    ///         将系统时钟发送到MCU中，并显示MCU的时钟 　　                 *　
    ///目    的:Timer演示　　                                               *
    ///说    明:                                                            *
    ///注    意:                                                            *
    ///日    期:2011年9月30日                                               *
    ///编 程 者:胡玉鑫                                                      *
    ///-----------Timer演示(苏州大学飞思卡尔嵌入式系统研发中心)-------------*
    public partial class Timer : Form
    {
        //委托,将从串口接收到的数据显示到接收框里面
        delegate void handleinterfaceupdatedelegate(Object textbox,
                                                    string text);
        //串口默认情况
        private string msg = "无校验,8位数据位,1位停止位";
        private string str = "串口号、波特率:";
        
        private byte data = 0;//串口字符命令标志
        private byte commandType = 0;//串口字符命令标志
        private byte tmrCount = 0;
        private string tmrStr = string.Empty;
 
        SCI sci = new SCI();    //要调用SCI类中所定义的函数
        ///-----------------------------------------------------------------*
        /// <summary>                                                       *
        /// 函 数 名:Timer:类Timer的构造函数                                *
        /// 功    能:完成窗体的初始化工作                                   *
        /// 函数调用:InitializeComponent                                    *
        /// </summary>                                                      *
        ///-----------------------------------------------------------------*
        public Timer()
        {
            CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
        }
        ///-----------------------------------------------------------------*
        /// <summary>                                                       *
        /// 对    象:Timer:窗体                                             *
        /// 事    件:Load                                                   *
        /// 功    能:执行加载窗体程序,自动获得串口号                        *
        ///          同时在标签LblSCI中显示串口相关信息                     *
        /// 函数调用:无                                                     *
        /// </summary>                                                      *
        /// <param name="sender"></param>                                   *
        /// <param name="e"></param>                                        *
        /// <remarks></remarks>                                             *
        ///-----------------------------------------------------------------*
        private void Timer_Load(object sender, EventArgs e)
        {
            //初始化时,按钮显示"打开串口(Open SCI)"
            this.BtnSCISwitch.Text = "打开串口";
            this.CbSCIBaud.Enabled = true;    //[波特率选择框]处于可用状态
            this.CbSCIComNum.Enabled = true;　//[串口选择框]处于可用状态

            //自动搜索串口,并将其加入到[串口选择框]中
            byte i;
            string[] SCIPorts;
            SCIPorts = System.IO.Ports.SerialPort.GetPortNames();
            this.CbSCIComNum.Items.Clear();//首先将现有的项清除掉
            for (i = 0; i < SCIPorts.Length; i++)
                //向[串口选择框]中添加搜索到的串口号
                this.CbSCIComNum.Items.Add(SCIPorts[i]);

            //设置各组合框的初始显示值
            this.CbSCIBaud.SelectedIndex = 0;
            this.CbSCIComNum.SelectedIndex = 0;
            

            //设置初始的串口号与波特率
            PublicVar.g_SCIComNum = this.CbSCIComNum.Text;
            PublicVar.g_SCIBaudRate = int.Parse(this.CbSCIBaud.Text);

            //显示当前串口信与状态信息
            this.lblSCISet.Text = "请先选择波特率与串口号,\n" +
                             "打开串口,然后发送数据";
            this.TimeStripStatusLabel.Text = "无操作,请先选择波特率与串口号,打开串口," +
                             "然后发送数据";
            
        }
        ///-----------------------------------------------------------------*
        /// <summary>                                                       *
        /// 对    象:CbSCIBaud                                              *
        /// 事    件:SelectedIndexChanged                                   *
        /// 功    能:改变当前串口波特率                                     *
        /// 函数调用:无                                                     *
        /// </summary>                                                      *
        /// <param name="sender"></param>                                   *
        /// <param name="e"></param>                                        *
        ///-----------------------------------------------------------------*
        private void CbSCIBaud_SelectedIndexChanged(object sender,
                                                    EventArgs e)
        {
            PublicVar.g_SCIBaudRate = int.Parse(this.CbSCIBaud.Text);
            this.TimeStripStatusLabel.Text = "过程提示:选择波特率";
        }

        ///-----------------------------------------------------------------*
        /// <summary>                                                       *
        /// 对    象:CbSCIComNum:串口选择框                                 *
        /// 事    件:SelectedIndexChanged                                   *
        /// 功    能:改变当前串口号                                         *
        /// 函数调用:无                                                     *
        /// </summary>                                                      *
        /// <param name="sender"></param>                                   *
        /// <param name="e"></param>                                        *
        ///-----------------------------------------------------------------*
        private void CbSCIComNum_SelectedIndexChanged(object sender,
                                                      EventArgs e)
        {
            PublicVar.g_SCIComNum = this.CbSCIComNum.Text;
            this.TimeStripStatusLabel.Text = "过程提示:选择串口号";
        }

        ///-----------------------------------------------------------------*
        /// <summary>                                                       *
        /// 对    象:BtnSCISwitch                                           *
        /// 事    件:Click                                                  *
        /// 功    能:(1)当开关显示为打开串口(Open SCI),则单击时执行打开串口 *
        ///          操作,并在标签LblSCI中显示选择的串口号与波特率,并在     *
        ///          状态条文本TimeStripStatusLabel中显示当前操作           *
        ///          (2)当开关显示为关闭串口(Close SCI),则单击时执行关闭串口*
        ///          操作,并在标签LblSCI中显示关闭的串口号与波特率,并在     *
        ///          状态条文本TimeStripStatusLabel中显示当前操作           *
        /// 函数调用:(1)SCIInit:串口初始化                                  *
        ///          (2)SCIClose:关闭串口                                   *
        /// </summary>                                                      *
        /// <param name="sender"></param>                                   *
        /// <param name="e"></param>                                        *
        ///-----------------------------------------------------------------*
        private void BtnSCISwitch_Click(object sender, EventArgs e)
        {
            bool Flag;//标记打开是否成功
            //根据按钮BtnSCISwitch显示内容执行打开或关闭串口操作
            if (this.BtnSCISwitch.Text.CompareTo("打开串口") == 0)
            {
                //提示当前正在执行打开串口操作
                this.TimeStripStatusLabel.Text = "过程提示:正在打开串口...";
                //进行串口的初始化,并用Flag返回结果
                Flag = sci.SCIInit(TimerserialPort, PublicVar.g_SCIComNum,
                            PublicVar.g_SCIBaudRate);

                if (Flag == true)//串口打开成功
                {
                    this.BtnSCISwitch.Text = "关闭串口";
                    //[串口选择框]处于禁用状态
                    this.CbSCIComNum.Enabled = false;
                    //[波特率选择框]处于禁用状态
                    this.CbSCIBaud.Enabled = false;
                    //状态上显示结果信息
                    this.TimeStripStatusLabel.Text = this.TimeStripStatusLabel.Text +
                                          "打开成功!";
                    this.lblSCISet.Text = str + PublicVar.g_SCIComNum
                        + "、" + PublicVar.g_SCIBaudRate + "\n" + msg;
                }
                else//串口打开失败
                {
                    this.TimeStripStatusLabel.Text = this.TimeStripStatusLabel.Text +
                                          "打开失败!";
                }
                this.pictureBox1.Image = Image.FromFile(Application.StartupPath + "\\..\\..\\Pictures\\earth.GIF");
            }
            else if (this.BtnSCISwitch.Text == "关闭串口")
            {
                //提示当前操作
                this.TimeStripStatusLabel.Text = "过程提示:正在关闭串口...";
                //执行关闭串口操作,并用Flag返回结果
                Flag = sci.SCIClose(this.TimerserialPort);
                if (Flag == true)
                {
                    this.BtnSCISwitch.Text = "打开串口";
                    //[串口选择框]处于可用状态
                    this.CbSCIComNum.Enabled = true;
                    //[波特率选择框]处于可用状态
                    this.CbSCIBaud.Enabled = true;
                    this.TimeStripStatusLabel.Text += "关闭成功!";
                }
                else//串口关闭失败
                {
                    this.TimeStripStatusLabel.Text += "关闭失败!";
                }
                this.pictureBox1.Image = Image.FromFile(Application.StartupPath + "\\..\\..\\Pictures\\earth.PNG");
            }

        }
        ///-----------------------------------------------------------------*
        /// <summary>                                                       *
        /// 对    象:TimerserialPort                                        *
        /// 事    件:DataReceived                                           *
        /// 功    能:串口接收数据                                           *
        /// 函数调用:(1)SCIReceiveData,串口接收函数                         *
        ///          (2)SCIUpdateRevtxtbox,更新文本框中的内容               *
        /// </summary>                                                      *
        /// <param name="sender"></param>                                   *
        /// <param name="e"></param>                                        *
        ///-----------------------------------------------------------------*
        private void TimerserialPort_DataReceived(object sender,
            System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            if (!TimerserialPort.IsOpen)
            {
                this.TimeStripStatusLabel.Text = "串口没打开！";
                return;
            }

            String str = String.Empty;
            bool Flag;//标记串口接收数据是否成功
            int len;  //标记接收的数据的长度

            //调用串口接收函数,并返回结果
            Flag = sci.SCIReceiveData(TimerserialPort, ref PublicVar.g_ReceiveByteArray);
            if (Flag == true)
            {
                //显示MCU端发来的数据，以便于调试
                len = PublicVar.g_ReceiveByteArray.Length;

                //对于字符串形式,考虑到可能有汉字,
                //直接调用系统定义的函数,处理整个字符串
                str = Encoding.Default.GetString(PublicVar.g_ReceiveByteArray);
                
                for (int i = 0; i < len; i++)
                {
                    data = PublicVar.g_ReceiveByteArray[i];     //获取命令类型
                    
                    if (data >= 130 && data <= 150)
                    {
                        commandType = data;
                        //准备使长度值=0
                        if (commandType == 135) this.tbMCUTime.Text = string.Empty;                        
                        continue;
                    }
                    
                    if (commandType == 135)
                    {
                        //timer模块
                        byte tmr = data;
                        tmrCount++;
                        tmrStr += (tmrCount > 1 ? ":" : "  ") + (tmr < 10 ? ("0" + tmr.ToString()) : tmr.ToString());
                        if (tmrCount >= 3)
                        {
                            SCIUpdateRevtxtbox(tbMCUTime, tmrStr);
                            tmrCount = 0;
                            tmrStr = string.Empty;
                            commandType = 0;
                        }
                    }

                }
            }
        }

        ///-----------------------------------------------------------------*
        /// <summary>                                                       *
        /// 函数名:SCIUpdateRevtxtbox                                       *
        /// 参  数:(1)textbox,Object类型,接收数据要放入的文本框             *
        ///        (2)text,string类型,要放入文本框的数据                    *
        /// 功  能:若串行接收与Object不在同一线程中运行，那么通过invoke     *
        ///        跨线程用串口接收到的数据来更新接收文本框中的数据         *
        /// 返  回:无                                                       *
        /// </summary>                                                      *
        /// <param name="textbox"></param>                                  *
        /// <param name="str"></param>                                      *
        ///-----------------------------------------------------------------*
        private void SCIUpdateRevtxtbox(Object textbox, string text)
        {
            //textbox显示文本与串口执行不在同一个线程中
            if (((TextBox)textbox).InvokeRequired)
            {
                handleinterfaceupdatedelegate InterFaceUpdate = new
                    handleinterfaceupdatedelegate(SCIUpdateRevtxtbox);
                this.Invoke(InterFaceUpdate, new object[] { textbox, text });
            }
            else
            {
                ((TextBox)textbox).Text += text;
                //把光标放在最后一行
                ((TextBox)textbox).SelectionStart =
                                           ((TextBox)textbox).Text.Length;
                //将文本空中的内容调整到当前插入符号位置
                ((TextBox)textbox).ScrollToCaret();
            }
        }
               
        ///-----------------------------------------------------------------*
        /// <summary>                                                       *
        /// 对    象:timerSystem                                            *
        /// 事    件:Tick                                                   *
        /// 功    能:系统时钟关联的每秒自动运行函数                         *
        /// 函数调用:无                                                     *
        /// </summary>                                                      *
        /// <param name="sender"></param>                                   *
        /// <param name="e"></param>                                        *
        ///-----------------------------------------------------------------*
        private void timerSystem_Tick(object sender, EventArgs e)
        {
            DateTime dt = DateTime.Now;
            int second = dt.Second;
            string secondStr = second.ToString();
            if (second < 10)
                secondStr = "0" + secondStr;
            this.tbSystemTime.Text = "  " + dt.ToString("t") + ":" + secondStr;
            //使按键复原
        }
        ///-----------------------------------------------------------------*
        /// <summary>                                                       *
        /// 对    象:btnTimeUpdate(发送按钮)                                *
        /// 事    件:Click                                                  *
        /// 功    能:将系统时钟发送给低端的函数                             *
        /// 函数调用:无                                                     *
        /// </summary>                                                      *
        /// <param name="sender"></param>                                   *
        /// <param name="e"></param>                                        *
        ///-----------------------------------------------------------------*
        private void btnTimeUpdate_Click(object sender, EventArgs e)
        {
            bool timeFlag = false;
            int i = 0;
            //如果串口没有打开
            if (!TimerserialPort.IsOpen)
            {
                //状态条进行提示
                this.TimeStripStatusLabel.Text += "请先打开串口!";
                return;
            }

            string[] systemTime = this.tbSystemTime.Text.Trim().Split(new char[] { ':' });

            int hourSend = Int32.Parse(systemTime[0]);
            int minSend = Int32.Parse(systemTime[1]);
            int secSend = Int32.Parse(systemTime[2]);

            PublicVar.g_SendByteArray = new byte[7];//0～35下标
            byte type = 135;
            byte len = 3;
            byte length = (byte)len;
            byte[] temp1 = new byte[1];
            byte[] temp2 = new byte[1];
            temp1 = System.Text.Encoding.Default.GetBytes("A");
            PublicVar.g_SendByteArray[0] = temp1[0];//加入帧头
            temp2 = System.Text.Encoding.Default.GetBytes("D");
            PublicVar.g_SendByteArray[1] = length;//加入有效数据长度
            PublicVar.g_SendByteArray[2] = type;//加入功能标志
            PublicVar.g_SendByteArray[3] = (byte)hourSend;
            PublicVar.g_SendByteArray[4] = (byte)minSend;
            PublicVar.g_SendByteArray[5] = (byte)secSend;
            i = 6;
            PublicVar.g_SendByteArray[i] = temp2[0];//加入帧尾

            //发送全局变量_SendByteArray中的数据,并返回结果
            timeFlag = sci.SCISendData(this.TimerserialPort, ref PublicVar.g_SendByteArray);

            if (timeFlag == true)//数据发送成功
                this.TimeStripStatusLabel.Text += "系统时间发送成功!";
            else
                this.TimeStripStatusLabel.Text += "系统时间发送失败!";

        }
        ///-----------------------------------------------------------------*
        /// <summary>                                                       *
        /// 对    象:Timer                                                  *
        /// 事    件:FormClosing                                            *   
        /// 功    能:关闭窗体时,确保串口已经关闭                            *
        /// 函数调用:SCIClose                                               *
        /// </summary>                                                      *
        /// <param name="sender"></param>                                   *
        /// <param name="e"></param>                                        *
        ///-----------------------------------------------------------------*
        private void Timer_FormClosing(object sender,
            FormClosingEventArgs e)
        {
            bool Flag;//标记串口关闭是否成功

            if (TimerserialPort.IsOpen)//串口没有关闭
            {
                //关闭串口并用Flag返回结果
                Flag = sci.SCIClose(this.TimerserialPort);

                if (Flag == true)
                    e.Cancel = false;//如果串口关闭成功，则激活窗体关闭按钮
                else
                {
                    e.Cancel = true;//如果串口关闭不成功，则禁用窗体关闭按钮
                    this.TimeStripStatusLabel.Text = "过程提示:请先关闭串口!";
                }
            }
        }
        
    }
}