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

namespace SerialPort
{
    ///---------------------------------------------------------------------*
    ///KB 　   :KB演示　　　                                                *
    ///功能描述:测试KB串口通信是否正常　                                    *
    ///         敲击扩展板上得键盘，在文本框中接收敲击的值                  *　
    ///目    的:KB演示　　                                                  *
    ///说    明:                                                            *
    ///注    意:                                                            *
    ///日    期:2011年9月30日                                               *
    ///编 程 者:胡玉鑫                                                      *
    ///-----------KB演示(苏州大学飞思卡尔嵌入式系统研发中心)-------------*
    public partial class KB : 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 string tmrStr = string.Empty;
        PictureBox[] kb = new PictureBox[16];
        Label[] lblKB = new Label[16];
        private char[] KBBoard ={ '7', '4', '1', '0',
                                  '8', '5', '2', 'A', 
                                  '9', '6', '3', 'B',
                                  'C', 'D', 'E', 'F' };
        private byte KBi = 0;
        
        SCI sci = new SCI();    //要调用SCI类中所定义的函数
        ///-----------------------------------------------------------------*
        /// <summary>                                                       *
        /// 函 数 名:KB:类KB的构造函数                                      *
        /// 功    能:完成窗体的初始化工作                                   *
        /// 函数调用:InitializeComponent                                    *
        /// </summary>                                                      *
        ///-----------------------------------------------------------------*
        public KB()
        {
            CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
        }
        ///-----------------------------------------------------------------*
        /// <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.KBstatus.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.KBstatus.Text = "过程提示:选择波特率";
        }
        ///-----------------------------------------------------------------*
        /// <summary>                                                       *
        /// 对    象:KB:窗体                                                *
        /// 事    件:Load                                                   *
        /// 功    能:执行加载窗体程序,自动获得串口号                        *
        ///          同时在标签LblSCI中显示串口相关信息                     *
        /// 函数调用:无                                                     *
        /// </summary>                                                      *
        /// <param name="sender"></param>                                   *
        /// <param name="e"></param>                                        *
        /// <remarks></remarks>                                             *
        ///-----------------------------------------------------------------*
        private void KB_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.KBstatus.Text = "无操作,请先选择波特率与串口号,打开串口," +
                             "然后发送数据";
            //键盘界面初始化
            for (i = 0; i < 16; i++)
            {
                kb[i] = new PictureBox();
                this.gbKeyBoard.Controls.Add(kb[i]);
                kb[i].Location = new System.Drawing.Point(45 + 50 * (i % 4), 30 + 50 * (i / 4));
                kb[i].Name = i.ToString();
                kb[i].Size = new System.Drawing.Size(48, 48);
                kb[i].Image = Image.FromFile(Application.StartupPath + "\\..\\..\\Pictures\\KeyUp.BMP");
                kb[i].Click += new EventHandler(gbKeyBoard_Enter);//这是一个委托 是给PictureBox加上单击的事件

                lblKB[i] = new Label();
                kb[i].Controls.Add(lblKB[i]);
                lblKB[i].Location = new System.Drawing.Point(16, 16);
                lblKB[i].Text = KBBoard[i].ToString();
                lblKB[i].Size = new System.Drawing.Size(12, 15);
                lblKB[i].BackColor = Color.Transparent;
                lblKB[i].ForeColor = Color.Red;
                lblKB[i].Font = new Font("宋体", 12);
            }
           
        }
        ///-----------------------------------------------------------------*
        /// <summary>                                                       *
        /// 对    象:gbKeyBoard                                             *
        /// 事    件:Enter                                                  *
        /// 功    能:直接点击键盘按键而运行的关联函数                       *
        /// 函数调用:无                                                     *
        /// </summary>                                                      *
        /// <param name="sender"></param>                                   *
        /// <param name="e"></param>                                        *
        ///-----------------------------------------------------------------*
        private void gbKeyBoard_Enter(object sender, EventArgs e)
        {
            PublicVar.g_SendByteArray = new byte[2];
            PublicVar.g_SendByteArray[0] = 134; //134表示处理键盘程序

            bool Flag = false;

            if (!KBserialPort.IsOpen)
            {
                this.KBstatus.Text = "串口没打开，请先打开串口";
                return;
            }
            ((PictureBox)sender).Image = Image.FromFile(Application.StartupPath + "\\..\\..\\Pictures\\KeyDown.BMP");
            if ((((PictureBox)sender).Name).Length == 1)
                PublicVar.g_SendByteArray[1] = (byte)KBBoard[Convert.ToByte((((PictureBox)sender).Name).Substring(0, 1))];//取下标值对应按键发送
            else
                PublicVar.g_SendByteArray[1] = (byte)KBBoard[Convert.ToByte((((PictureBox)sender).Name).Substring(0, 2))];//取下标值对应按键发送

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

            if (Flag == true)//数据发送成功
                this.KBstatus.Text += "按键发送成功!";
            else
                this.KBstatus.Text += "按键发送失败!";

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

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

                if (Flag == true)
                    e.Cancel = false;//如果串口关闭成功，则激活窗体关闭按钮
                else
                {
                    e.Cancel = true;//如果串口关闭不成功，则禁用窗体关闭按钮
                    this.KBstatus.Text = "过程提示:请先关闭串口!";
                }
            }
        }
        
        ///-----------------------------------------------------------------*
        /// <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>                                                       *
        /// 对    象:BtnSCISwitch                                           *
        /// 事    件:Click                                                  *
        /// 功    能:(1)当开关显示为打开串口(Open SCI),则单击时执行打开串口 *
        ///          操作,并在标签LblSCI中显示选择的串口号与波特率,并在     *
        ///          状态条文本KBstatus中显示当前操作                      *
        ///          (2)当开关显示为关闭串口(Close SCI),则单击时执行关闭串口*
        ///          操作,并在标签LblSCI中显示关闭的串口号与波特率,并在     *
        ///          状态条文本KBstatus中显示当前操作                      *
        /// 函数调用:(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.KBstatus.Text = "过程提示:正在打开串口...";
                //进行串口的初始化,并用Flag返回结果
                Flag = sci.SCIInit(KBserialPort, PublicVar.g_SCIComNum,
                            PublicVar.g_SCIBaudRate);

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

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

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

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

                //对于字符串形式,考虑到可能有汉字,
                //直接调用系统定义的函数,处理整个字符串
                //十进制和十六进制形式按字节进行处理
                for (int i = 0; i < len; i++)
                {
                    data = PublicVar.g_ReceiveByteArray[i];     //获取命令类型
                    if (data >= 130 && data <= 150)
                    {
                        commandType = data;
                        //准备使长度值=0
                        continue;
                    }
                    
                    if (commandType == 134)
                    {
                        //键盘测试模块
                        byte kbKey = data;
                        for (byte j = 0; j < 16; j++)
                            if (KBBoard[j] == (char)kbKey)
                            {
                                kb[j].Image = Image.FromFile(Application.StartupPath + "\\..\\..\\Pictures\\KeyDown.BMP");
                                KBi = j;
                                SCIUpdateRevtxtbox(tbKBShow, KBBoard[j].ToString());
                                break;
                            }
                    }
                 }
            }
        }

    }
}