異世界


2012年6月24日 星期日

SerialPort Class 擴充 (二)

將SerialPort 封裝在內部,改善直接使用SerialPort Class 的問題。

改善後的 JgeComport Class :

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.IO;
using System.Threading;
using System.Diagnostics;
 
namespace SBM75e_4
{
    /// <summary>
    /// 事件委派宣告
    /// </summary>
    public delegate void jgecomEventHandler(object sender, jgecomEventArgs e);
 
    /// <summary>
    /// 定義專用事件參數類別
    /// </summary>
    public class jgecomEventArgs : EventArgs
    {
        private string mComName;
        private Stream mMSG = new MemoryStream();
        //Byte[] mMSG = new Byte[1024];
 
        //public jgecomEventArgs(byte[] msg, string commName)
        public jgecomEventArgs(Stream msg, string commName)
        {
            MSG = msg;
            NAME = commName;
        }
        
        public string NAME
        {
            get { return mComName; }
            private set { mComName = value; }
        }
 
        //public byte[] MSG
        public Stream MSG
        {
            get { return mMSG; }
            private set { mMSG = value; }
        }
    }
 
    
    // Invok 跳板的委派宣告
    delegate void onInvok(Stream buffer);
 
    class JgeComport
    {
        #region 靜態公用函式
        /// <summary>
        /// 將 Byte陣列 轉為 Stream
        /// </summary>
        /// <returns>Stream</returns>
        public static Stream BytesToStream(byte[] bytes)
        {
            Stream stream = new MemoryStream(bytes);
            return stream;
        }
 
        public static Stream BytesToStream(byte[] bytes, int Length)
        {
            Stream stream = new MemoryStream(bytes, 0, Length);
            return stream;
        }
        /// <summary>
        /// 將 Stream 轉為 Byte陣列
        /// </summary>
        public static byte[] StreamToBytes(Stream stream)
        {
            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);
 
            /*將 stream 指針指向開頭*/
            stream.Seek(0, SeekOrigin.Begin);
            return bytes;
        }
        #endregion
 
        /// <summary>
        /// 委派宣告
        /// </summary>
        private delegate void SetReceived(Stream msg, string ip);
 
        /// <summary>
        /// 委派欄位
        /// </summary>
        private SetReceived mSetReceivedDlg;
 
        /// <summary>
        /// Received 事件
        /// </summary>
        public event jgecomEventHandler Received;
 
        /// <summary>
        /// 委派處理函式
        /// </summary>
        private void OnReceivedText(Stream msg, string commName)
        {
            jgecomEventArgs e = new jgecomEventArgs(msg, commName);
 
            if (Received != null) //. 當事件變數不為 null 則執行之
            {
                Received(this, e);
            }
        }
 
        /// <summary>
        /// 儲存擁有者
        /// </summary>
        private object mOwner;
 
        //========================================================================
 
        /// <summary>
        /// SerialPort 物件,設為public 以便直接取用其屬性(偷懶的作法)
        /// </summary>
        private SerialPort comport;
 
        /// <summary>
        /// 內部使用變數
        /// </summary>
        private Boolean mReceiving; // 能讓DoReceive方法內的While迴圈停止        
        private Thread mRxThread;  // Thread型別的變數 mRxThread,則是為了產生執行緒所宣告
 
 
        /// <summary>
        /// 建構式
        /// </summary>
        public JgeComport(object Owner)
        {
            mOwner = Owner;
            mSetReceivedDlg = OnReceivedText;/*設定委派處理函式*/
            comport = new SerialPort();
        }
 
        /// <summary>
        /// Connect 方法-1
        /// </summary>
        public void Connect(string portName,int baudRate,Parity parity,int dataBits,StopBits stopBits)
        {
            comport.PortName = portName;
            comport.BaudRate=baudRate;
            comport.Parity=parity;
            comport.DataBits=dataBits;
            comport.StopBits = stopBits;
 
            Connect();
        }
 
        /// <summary>
        /// Connect 方法-2
        /// </summary>
        public void Connect()
        {               
            if (!comport.IsOpen)
            {
                comport.Open();
 
                // 產生執行緒來執行自訂的DoReceive方法
                mReceiving = true;
                mRxThread = new Thread(DoReceive);
                //mRxThread = new Thread(DoReceiveEx);
                mRxThread.IsBackground = true;
                mRxThread.Start();
            }
        }
 
        #region 以執行緒處裡Rx事件
        /// <summary>
        /// 以執行緒處裡Rx事件
        /// </summary>
        /// 
        /* OnReceive 事件跳板 */
        private void onInvoked(Stream buffer)
        {
            OnReceivedText(buffer, comport.PortName.ToString());
        }
        /* Rx 執行緒 */
        private void DoReceive()
        {
            Byte[] buffer = new Byte[1024];
 
            while (mReceiving)
            {
                if (comport.BytesToRead > 0)
                {
                    Thread.Sleep(312); // Sleep 一段時間,用以讀取個多數據(該處可加入判斷式,進行更多的條件讀取)
 
                    Int32 length = comport.Read(buffer, 0, buffer.Length);
                    Array.Resize(ref buffer, length);
                    onInvok d = new onInvok(onInvoked);
                    /* Invoke */((System.Windows.Forms.Form)mOwner).Invoke(d, new Object[] { BytesToStream(buffer) });
                    Array.Resize(ref buffer, 1024);
                }
                Thread.Sleep(16);
            }
        }
        #endregion
        
        #region SerialPort 對應之屬性
        /// <summary>
        /// 要使用的連接埠 (例如 COM1)
        /// </summary>
        public string PortName
        {
            get
            {
                return comport.PortName;
            }
            set
            {
                comport.PortName = value;
            }
        }
 
        /// <summary>
        /// 傳輸速率: 2400,4800,9600,19200,38400,57600,115200
        /// </summary>
        public int BaudRate
        {
            get
            {
                return comport.BaudRate;
            }
            set
            {
                comport.BaudRate = value;
            }
        }
 
        /// <summary>
        /// System.IO.Ports.Parity
        /// </summary>
        public System.IO.Ports.Parity Parity
        {
            get
            {
                return comport.Parity;
            }
            set
            {
                comport.Parity = value;
            }
        }
 
        /// <summary>
        /// 資料位元值
        /// </summary>
        public int DataBits
        {
            get
            {
                return comport.DataBits;
            }
            set
            {
                comport.DataBits = value;
            }
        }
 
        /// <summary>
        /// System.IO.Ports.StopBits
        /// </summary>
        public System.IO.Ports.StopBits StopBits
        {
            get
            {
                return comport.StopBits;
            }
            set
            {
                comport.StopBits = value;
            }
        }
 
        /// <summary>
        /// 取得值,指出 SerialPort 物件的開啟或關閉狀態。
        /// </summary>
        public Boolean IsOpen
        {
            get
            {
                return comport.IsOpen;
            }
            set
            {
            }
        }
        #endregion
 
        /// <summary>
        /// 關閉連接埠連線
        /// </summary>
        public void Close()
        {
            comport.Close();
        }
 
        /// <summary>
        /// 將指定的字串寫入序列埠
        /// </summary>
        public void Write(string text)
        {
            comport.Write(text);
        }
 
        /// <summary>
        /// 使用緩衝區中的資料,將指定的位元組數目寫入序列埠。
        /// </summary>
        public void Write(byte[] buffer,int offset,int count)
        {
            comport.Write(buffer, offset, count);
        }
 
        /// <summary>
        /// 使用緩衝區中的資料,將指定的字元數目寫入序列埠。
        /// </summary>
        public void Write(char[] buffer,int offset,int count)
        {
            comport.Write(buffer, offset, count);
        }
 
        /// <summary>
        /// 使用Stream中的資料,將指定的字元數目寫入序列埠。
        /// </summary>
        public void Write(Stream buffer, int offset, int count)
        {
            byte[] bytes = new byte[buffer.Length];
            comport.Write(bytes, offset, count);
        }
 
        /// <summary>
        /// 將指定字串和 NewLine 值寫入輸出緩衝區
        /// </summary>
        public void WriteLine(String text)
        {
            comport.WriteLine(text);
        }
 
 
        
 
 
    }
}


 


使用該 Class


JgeComport My232 = new JgeComport(this);
My232.Connect("COM2", 57600, Parity.None, 8, StopBits.One);
My232.Received += this.onReceived;
 
 
string ss = "1234567890";
Byte[] bytes = System.Text.Encoding.ASCII.GetBytes(ss);
Stream stream = new MemoryStream(bytes);
My232.Write(ss);
My232.Write(bytes, 0, bytes.Length);
My232.Write(stream, 0, (int)(stream.Length));

事件程式


private void onReceived(object sender, jgecomEventArgs e)
        {
            switch (e.NAME.ToString())
            {
                case "COM2":
                    Byte[] bytes = new Byte[1024];
                    bytes = JgeComport.StreamToBytes(e.MSG);
                    
                    string ss = System.Text.Encoding.ASCII.GetString(bytes);
                    textBox1.AppendText(ss + Environment.NewLine);
 
                    textBox1.Text += String.Format("{0}{1}", BitConverter.ToString(bytes), Environment.NewLine); //Environment.NewLine => \r\n
                    label2.Text = bytes.Length.ToString();
                    break;
                default:
                    break;
            }
        }



ClassDiagram:


image

沒有留言:

張貼留言