2016년 6월 20일 월요일

C# 간단한 시리얼 통신 라이브러리 소스코드 - simple c# source code for serial communication

 using System;  
 using System.Collections.Generic;  
 using System.Diagnostics;  
 using System.IO.Ports;  
 using System.Linq;  
 using System.Text;  
 using System.Threading;  
 using System.Threading.Tasks;  
   
 namespace SerialCommLib  
 {        
   public class SerialComm
   {    
     public delegate void DataReceivedHandlerFunc(byte[] receiveData);  
     public DataReceivedHandlerFunc DataReceivedHandler;  
   
     public delegate void DisconnectedHandlerFunc();  
     public DisconnectedHandlerFunc DisconnectedHandler;
   
     private SerialPort serialPort;  
      
     public bool IsOpen   
     {   
       get   
       {   
         if (serialPort != null) return serialPort.IsOpen;  
         return false;  
       }   
     }  
      
     // serial port check
     private Thread threadCheckSerialOpen;  
     private bool isThreadCheckSerialOpen = false;  
   
     public SerialComm()  
     {  
     }  
   
     public bool OpenComm(string portName, int baudrate, int databits, StopBits stopbits, Parity parity, Handshake handshake)  
     {  
       try  
       {  
         serialPort = new SerialPort();  
   
         serialPort.PortName = portName;  
         serialPort.BaudRate = baudrate;  
         serialPort.DataBits = databits;  
         serialPort.StopBits = stopbits;  
         serialPort.Parity = parity;  
         serialPort.Handshake = handshake;  
   
         serialPort.Encoding = new System.Text.ASCIIEncoding();  
         serialPort.NewLine = "\r\n";  
         serialPort.ErrorReceived += serialPort_ErrorReceived;     
         serialPort.DataReceived += serialPort_DataReceived; 
   
         serialPort.Open();  
   
         StartCheckSerialOpenThread();  
         return true;  
       }  
       catch (Exception ex)  
       {  
         Debug.WriteLine(ex.ToString());  
         return false;  
       }  
     }  
   
     public void CloseComm()  
     {  
       try  
       {  
         if (serialPort != null)  
         {  
           StopCheckSerialOpenThread();  
           serialPort.Close();  
           serialPort = null;  
         }  
       }  
       catch (Exception ex)  
       {  
         Debug.WriteLine(ex.ToString());  
       }  
     }  
   
     public bool Send(string sendData)  
     {  
       try  
       {  
         if (serialPort != null && serialPort.IsOpen)  
         {  
           serialPort.Write(sendData);  
           return true;  
         }          
       }  
       catch (Exception ex)  
       {  
         Debug.WriteLine(ex.ToString());  
       }  
       return false;  
     }  
   
     public bool Send(byte[] sendData)  
     {  
       try  
       {  
         if (serialPort != null && serialPort.IsOpen)  
         {  
           serialPort.Write(sendData, 0, sendData.Length);  
           return true;  
         }  
       }  
       catch (Exception ex)  
       {  
         Debug.WriteLine(ex.ToString());  
       }  
       return false;  
     }  
   
     public bool Send(byte[] sendData, int offset, int count)  
     {  
       try  
       {  
         if (serialPort != null && serialPort.IsOpen)  
         {  
           serialPort.Write(sendData, offset, count);  
           return true;  
         }  
       }  
       catch (Exception ex)  
       {  
         Debug.WriteLine(ex.ToString());  
       }  
       return false;  
     }  
   
     private byte[] ReadSerialByteData()  
     {  
       serialPort.ReadTimeout = 100;  
       byte[] bytesBuffer = new byte[serialPort.BytesToRead];  
       int bufferOffset = 0;  
       int bytesToRead = serialPort.BytesToRead;  
   
       while (bytesToRead > 0)  
       {  
         try  
         {  
           int readBytes = serialPort.Read(bytesBuffer, bufferOffset, bytesToRead - bufferOffset);  
           bytesToRead -= readBytes;  
           bufferOffset += readBytes;  
         }  
         catch (TimeoutException ex)  
         {  
           Debug.WriteLine(ex.ToString());  
         }  
       }  
   
       return bytesBuffer;  
     }  
   
     private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)  
     {  
       try  
       {  
         byte[] bytesBuffer = ReadSerialByteData();  
         string strBuffer = Encoding.ASCII.GetString(bytesBuffer);  

         if (DataReceivedHandler != null)  
           DataReceivedHandler(bytesBuffer);  
   
         Debug.WriteLine("received(" + strBuffer.Length + ") : " + strBuffer);     
       }  
       catch (Exception ex)  
       {  
         Debug.WriteLine(ex.ToString());  
       }  
     }  
   
     private void serialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)  
     {  
       Debug.WriteLine(e.ToString());  
     }  
      
     private void StartCheckSerialOpenThread()  
     {   
       isThreadCheckSerialOpen = true;  
       threadCheckSerialOpen = new Thread(new ThreadStart(ThreadCheckSerialOpen));  
       threadCheckSerialOpen.Start();  
     }  
   
     private void StopCheckSerialOpenThread()  
     {  
       if (isThreadCheckSerialOpen)  
       {  
         isThreadCheckSerialOpen = false;  
         if (Thread.CurrentThread != threadCheckSerialOpen)  
           threadCheckSerialOpen.Join();
       }  
     }  
   
     private void ThreadCheckSerialOpen()  
     {  
       while (isThreadCheckSerialOpen)  
       {  
         Thread.Sleep(100);  
   
         try  
         {  
           if (serialPort == null || !serialPort.IsOpen)  
           {  
             Debug.WriteLine("seriaport disconnected");  
             if (DisconnectedHandler != null)  
               DisconnectedHandler();  
             break;  
           }  
         }  
         catch (Exception ex)  
         {  
           Debug.WriteLine(ex.ToString());  
         }  
       }  
     }  
   }  
 }  
   


< SerialComm 사용 >

using System.IO.Ports;

using SerialCommLib;
...
SerialComm serial = new SerialComm();
serial.DataReceivedHandler = DataReceivedHandler;
serial.DisconnectedHandler = DisconnectedHandler;
...
serial.OpenComm("COM3", 9600, 8, StopBits.One, Parity.None, Handshake.None);
...
serial.CloseComm();

private void DataReceivedHandler(byte[] receiveData)
{
    // do something with receiveData here
}

private void DisconnectedHandler()
{
    Console.WriteLine("serial disconnected");
}

* 라이브러리 사용은 시리얼 데이터 수신과 연결종료 이벤트 핸들러를 등록해서 콜백으로 받아서 처리하는 방식으로 간단하게 사용할 수 있다.

C# SerialPort 클래스는 이벤트 수신 방식과 쓰레드 방식 두 가지로 사용할 수 있는데 쓰레드 방식보다 이벤트 수신 방식이 더 간단하고 직관적이다.
SerialPort 클래스의 Read 계열 메소드는 블러킹 방식으로 동작하기때문에 데이터 수신 이벤트 발생시 반드시 BytesToRead 에 명시된 모든 바이트를 읽어서 수신버퍼를 비워줘야한다.