C〓〓を使ってシリアルダイヤルを実現するSIMカード通信[修正版]

39373 ワード


第一版でC萼を使ってシリアルダイヤルを実現するSIMカード通信のコードには、いくつかの実際的な問題があり、繰り返しテストと実際の使用を経て、元のコードをいくつか改良しました.
 
まず、ブログ園のㄒ樹炪啧?ㄖさんがダイヤル指令ATDを出した後に、Thread.Sleep(20*1000)の方法を使って20秒後に電話をかける必要はなく、AutoReetEventに変えて処理しても、スレッドを死なせる必要がないなど、プログラムの性能を向上させることができます.しかし、修正後の効果は理想的ではなく、Thread.Sleep(20*1000)の方法を使って、すばやいです.
 
第二に、ダイヤルやサーバーなどのハードウェア機器の違いにより、フィードバック情報の速度が一致しなくなりました.以前はThread.Sleep()方法で固定秒数をバインドしてから戻り情報を確認する方式に一定の問題があります.次のコードに変えればいいです.
int i = 0;
while (read.Trim() == "" && i <15)
{
    Thread.Sleep(100);
    i++;
}

if (read.Contains("ATH") && read.Contains("OK"))
{  ......  }
残りは詳しく紹介しないで、コードを見ればいいです.
 
MySerialPort類
COMシリアルポートに接続された各ダイヤルに対して、MySerialPortオブジェクトを実装します.コードは以下の通りです.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Threading;

namespace Con_SerialPortExample
{

    public class MySerialPort
    {
        private SerialPort com;

        public MySerialPort(string _portName)
        {
            this.com = new SerialPort();
            //this.autoResetEvent_HasModem = new AutoResetEvent(true);
            //this.autoResetEvent_Dialing = new AutoResetEvent(false);

            //      
            this.com.DataReceived += new SerialDataReceivedEventHandler(com_DataReceived);
            //   
            com.PortName = _portName;
            this.PortName = _portName;

            // BaudRate      
            com.BaudRate = 9600; //   

            //          (RTS)   。
            com.RtsEnable = true; //         Request   To   Send              ,         。

            //    Data Terminal Ready (DTR)   。  xugang 2012.8.20   
            //com.DtrEnable = true; //Data   Terminal   Ready                  ,            。 

            try
            {
                com.Open();
            }
            catch //(Exception)
            {
                Close();
            }

        }

        public MySerialPort(string _portName, int _baudRate)
            : this(_portName)
        {
            if (_baudRate != 0)
            {
                // BaudRate      
                com.BaudRate = _baudRate;
            }
        }


        private string portName;
        //    
        public string PortName
        {
            get { return portName; }
            set { portName = value; }
        }

        // BaudRate      
        public int BaudRate
        {
            get { return com.BaudRate; }
            set { com.BaudRate = value; }
        }

        private bool isWorking;
        //        
        public bool IsWorking
        {
            get { return isWorking; }
            set { isWorking = value; }
        }

        //private enum AutoResetEvent_Type
        //{
        //   None, HasModem, Dialing
        //}
        //private AutoResetEvent autoResetEvent_HasModem;
        //private AutoResetEvent autoResetEvent_Dialing;
        //private AutoResetEvent_Type autoResetEvent_Type = AutoResetEvent_Type.None;
        //private bool enableUse;
        private DateTime lastUseTime = DateTime.MinValue;
        //          (          )
        public bool EnableUse
        {
            get 
            {
                TimeSpan span = DateTime.Now - lastUseTime;
                return span.TotalSeconds >= 60; 
            }
            //set { enableUse = value; }
        }

        //               
        public bool HasModem()
        {
            //this.autoResetEvent_Type = AutoResetEvent_Type.HasModem;

            //read = ""; //       
            WriteSerial("AT\r
"); //Thread.Sleep(500); //this.autoResetEvent_HasModem.WaitOne(5 * 1000); //this.autoResetEvent_Type = AutoResetEvent_Type.None; int i = 0; while (read.Trim() == "" && i < 40) { Thread.Sleep(100); i++; } Console.WriteLine(read.TrimEnd('\r', '
')); //Console.Write(read); //if (read.Contains("AT") && read.Contains("OK")) if (read.Contains("OK")) { Console.WriteLine(this.com.PortName + " !"); return true; } else { Console.WriteLine(this.com.PortName + " !"); return false; } } // public void Dialing(string _SIM) { IsWorking = true; // try { //this.autoResetEvent_Type = AutoResetEvent_Type.Dialing; read = ""; // StringBuilder sb = new StringBuilder(36); sb.Append(this.com.PortName); sb.Append(" SIM :"); sb.Append(_SIM); sb.Append(" ..."); Console.WriteLine(sb.ToString()); WriteSerial(string.Format("ATD{0};\r
", _SIM)); System.Threading.Thread.Sleep(20 * 1000); //this.autoResetEvent_Dialing.WaitOne(20 * 1000); //this.autoResetEvent_Type = AutoResetEvent_Type.None; read = ""; // WriteSerial("ATH\r
"); //this.autoResetEvent.WaitOne(1000); int i = 0; while (read.Trim() == "" && i <15) { Thread.Sleep(100); i++; } Console.WriteLine(read); if (read.Contains("ATH") && read.Contains("OK")) { Console.WriteLine(this.com.PortName + " !"); } else { read = ""; // //System.Threading.Thread.Sleep(1000); WriteSerial("ATH\r
"); //this.autoResetEvent.WaitOne(1000); i = 0; while (read.Trim() == "" && i < 20) { Thread.Sleep(100); i++; } Console.WriteLine(read); if (read.Contains("ATH") && read.Contains("OK")) { Console.WriteLine(this.com.PortName + " !"); } else { //IsWorking = false; // string strExc = this.com.PortName + ""; Console.WriteLine(strExc); throw new Exception(strExc); } } } catch (Exception ex) { throw ex; } finally { IsWorking = false; // } } /// <summary> ////// </summary> /// <param name="s"> </param> private void WriteSerial(string s) { //this.autoResetEvent_HasModem.WaitOne(20*1000); //mLogger.Info(s); byte[] buff = Encoding.ASCII.GetBytes(s); try { this.com.Write(buff, 0, buff.Length); } catch (Exception ex) { //WriteExecLog.Writing(ex); Console.WriteLine(ex.Message); } } //int n = 0; string read = ""; // void com_DataReceived(object sender, SerialDataReceivedEventArgs e) { if (sender is SerialPort) { try { Thread.Sleep(500); read = ""; // SerialPort mySerial = sender as SerialPort; if (mySerial.IsOpen == false) { mySerial.Open(); } // //read += mySerial.ReadLine().Trim(); //Console.WriteLine(mySerial.PortName + " " + n.ToString() + " :" + read); // byte[] readBuffer = new byte[1024]; int count = mySerial.Read(readBuffer, 0, 1023); if (count > 0) { read = System.Text.Encoding.ASCII.GetString(readBuffer, 0, count); //Console.WriteLine(read); } //AT //if (autoResetEvent_Type == AutoResetEvent_Type.HasModem // && read.Contains("OK")) //{ // this.autoResetEvent_HasModem.Set(); //} //ATD //if (autoResetEvent_Type == AutoResetEvent_Type.Dialing // && (read.Contains("ERROR") || read.Contains("BUSY") || read.Contains("OK") || read.Contains("NO CARRIER")) // ) //{ // this.autoResetEvent_Dialing.Set(); //} } catch (TimeoutException) { return; //xg : ! } catch (Exception) { return; //xg : ! } //finally //{ // this.autoResetEvent_HasModem.Set(); //} } } //private string ReadSerial() //{ // while (_keepReading) // { // if (com.IsOpen) // { // //byte[] readBuffer = new byte[com.ReadBufferSize + 1]; // byte[] readBuffer = new byte[10]; // try // { // //int count = com.Read(readBuffer, 0, com.ReadBufferSize); // int count = com.Read(readBuffer, 0, 9); // String SerialIn = System.Text.Encoding.ASCII.GetString(readBuffer, 0, count); // if (count != 0) // { // return SerialIn; // } // } // catch (TimeoutException) // { // return ""; // } // } // else // { // TimeSpan waitTime = new TimeSpan(0, 0, 0, 0, 50); // Thread.Sleep(waitTime); // } // } // return ""; //} // public void Close() { if (com != null) { com.Close(); com.Dispose(); } } } }
 
SerialPortList類
SerialPortListクラスを定義して、すべての接続上のダイヤルアップMySerialPortオブジェクトの管理とスケジューリング使用を実現します.コードは以下の通りです
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Threading;

namespace Con_SerialPortExample
{

    public class SerialPortList
    {
        //             
        private List<MySerialPort> al = null;
        //         
        public int WorkableCount
        {
            get
            {
                if (al == null) return 0;
                else return al.Count;
            }
        }

        private Dictionary<string, int> portBaudRate = null;
        //       
        public Dictionary<string, int> PortBaudRate
        {
            get { return portBaudRate; }
            set { portBaudRate = value; }
        }

        private bool hasPort = false;
        //             
        public bool HasPort
        {
            get { return hasPort; }
            //set { hasPort = value; }
        }

        private int reCheckMinutes = 30; //  30  
        //              
        public int ReCheckMinutes
        {
            get { return reCheckMinutes; }
            set { reCheckMinutes = value; }
        }

        #region        
        public SerialPortList() { }

        public SerialPortList(Dictionary<string, int> _portBaudRate)
        {
            this.portBaudRate = _portBaudRate;
        }
        public SerialPortList(int _reCheckMinutes)
        {
            this.reCheckMinutes = _reCheckMinutes;
        }
        public SerialPortList(Dictionary<string, int> _portBaudRate, int _reCheckMinutes)
        {
            this.portBaudRate = _portBaudRate;
            this.reCheckMinutes = _reCheckMinutes;
        }
        #endregion        

        /// <summary>
        ///                  
        /// </summary>
        public void GetSerialPortList()
        {
            al = new List<MySerialPort>();

            //   :          (  )
            string[] ports = SerialPort.GetPortNames();

            foreach (string port in ports)
            {
                MySerialPort mySerialPort = null;

                Console.WriteLine("" + port); //    

                //
                if (portBaudRate != null
                    && portBaudRate.ContainsKey(port)
                    && portBaudRate[port] != 0)
                {
                    mySerialPort = new MySerialPort(port, portBaudRate[port]);
                }
                else mySerialPort = new MySerialPort(port);

                bool ok = mySerialPort.HasModem();
                if (ok)
                {
                    al.Add(mySerialPort);
                }
                else
                {
                    mySerialPort.Close();
                    mySerialPort = null;
                }
            }

            //                
            hasPort = al.Count <= 0 ? false : true;
        }


        /// <summary>
        ///                   
        /// </summary>
        public void ReGetSerialPortList()
        {
            if (al == null) GetSerialPortList();
            else
            {
                //   :            (  )
                string[] portsName_2 = SerialPort.GetPortNames();

                //         >      COM
                if (portsName_2.Length > al.Count)
                {
                    Console.WriteLine(""); //    
                    foreach (string pName_2 in portsName_2)
                    {
                        //              
                        bool hasAt = al.Exists(delegate(MySerialPort port_1)
                        {
                            return pName_2 == port_1.PortName;
                        });

                        //               ,     !
                        if (!hasAt)
                        {
                            Console.WriteLine("" + pName_2); //    

                            MySerialPort mySerialPort = null;

                            //
                            if (portBaudRate != null
                                && portBaudRate.ContainsKey(pName_2)
                                && portBaudRate[pName_2] != 0)
                            {
                                mySerialPort = new MySerialPort(pName_2, portBaudRate[pName_2]);
                            }
                            else mySerialPort = new MySerialPort(pName_2);

                            bool ok = mySerialPort.HasModem();
                            if (ok)
                            {
                                al.Add(mySerialPort);
                            }
                            else
                            {
                                mySerialPort.Close();
                                mySerialPort = null;
                            }
                        }
                    }
                }
            }

            //                
            hasPort = al.Count <= 0 ? false : true;
        }

        /// <summary>
        ///                    (        )
        /// </summary>
        public void ReGetSerialPortList(int _reCheckMinutes)
        {
            //              
            reCheckMinutes = _reCheckMinutes;

            ReGetSerialPortList();//          
        }

        /// <summary>
        ///           
        /// </summary>
        public void ClearAllSerialPort()
        {
            if (al != null)
            {
                for (int i = 0; i < al.Count; i++)
                {
                    al[i].Close();
                    al[i] = null;
                }
                al = null;
            }

            if (portBaudRate != null)
            {
                portBaudRate = null;
            }
        }

        private int index_Number = -1;
        //      
        private int IndexNumber()
        {

            lock (this)
            {
                if (index_Number + 1 >= al.Count)
                {
                    if (al.Count == 0) index_Number = -1;
                    else index_Number = 0;
                }
                else
                {
                    index_Number++;
                }

                return index_Number;
            }

        }

        /// <summary>
        ///                 
        /// </summary>
        private void UseingSerialPort(string _SIM)
        {
            if (al == null) return;

            //        
            Monitor.Enter(al);

            MySerialPort getPort = null;
            try
            {
                //               
                int num = IndexNumber();

                if (num >= 0) //         
                {
                    getPort = al[num];
                    if (getPort != null && !getPort.IsWorking)
                    {
                        getPort.Dialing(_SIM); //  SIM     ,     
                    }
                }
                else
                {
                    //         ,     。
                    this.ReGetSerialPortList();
                }
            }
            catch
            {
                //       COM     ! (    )
                if (getPort != null)
                {
                    string re_PortName = getPort.PortName;
                    al.Remove(getPort); //       
                    getPort.Close();

                    MySerialPort mySerialPort = new MySerialPort(re_PortName);
                    bool ok = mySerialPort.HasModem();
                    if (ok)
                    {
                        al.Add(mySerialPort); //       
                    }
                    else
                    {
                        mySerialPort.Close();
                        mySerialPort = null;
                    }
                }
            }
            finally
            {
                //       
                Monitor.Pulse(al);
                //       
                Monitor.Exit(al);
            }
        }

        //        
        private DateTime dtCheck = DateTime.Now;

        /// <summary>
        ///      
        /// </summary>
        /// <param name="_SIM"></param>
        public void InvokingSerialPort(string _SIM)
        {
            if (hasPort == false)
            {
                //                 
                this.GetSerialPortList();
            }
            if (hasPort == true)
            {
                this.UseingSerialPort(_SIM);
                //Thread.Sleep(5000);
            }

            //        
            //if (dtCheck.AddMinutes(reCheckMinutes) <= DateTime.Now)
            if (dtCheck.AddMinutes(5) <= DateTime.Now)
            {
                //                   
                this.ReGetSerialPortList();
                dtCheck = DateTime.Now;
            }
        }

    }

}
 
テストコードは以下の通りです.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//
//using System.IO.Ports;
using System.Threading;
//using System.Collections;

namespace Con_SerialPortExample
{
    class Program
    {
        static void Main(string[] args)
        {
            //                  (      )
            Dictionary<string, int> _portBaudRate = new Dictionary<string, int>();
            _portBaudRate["COM1"] = 9600;
            _portBaudRate["COM2"] = 9600;
            _portBaudRate["COM7"] = 9600;

            SerialPortList list = new SerialPortList(_portBaudRate,5);

            try
            {
                //                 
                list.GetSerialPortList();

                if (list.HasPort == false)
                {
                    Console.WriteLine("");
                }

                while (list.HasPort)
                {
                    //      
                    list.InvokingSerialPort("13500000000"); 
                    Thread.Sleep(5000);
                }

                Console.WriteLine("");
            }
            finally
            {
                //           
                list.ClearAllSerialPort();
            }

            Console.ReadLine();
        }
    }
}