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 에 명시된 모든 바이트를 읽어서 수신버퍼를 비워줘야한다.