using log4net;
using log4net.Appender;
using log4net.Layout;
using log4net.Repository.Hierarchy;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Reflection;
using System.Text;
using System.Threading;
namespace SHARP_CLAS_UI
{
///
/// Serial Module을 제어하기 위한 클래스
///
public class Serial_Module
{
#region Enum
#endregion
#region Logger
///
/// Exception Log
///
private ILog ExceptionLog = LogManager.GetLogger("SerialException");
///
/// Exception Log 사용유무 확인
///
public bool UseExceptionLog { get; set; }
///
/// Exception Log를 기록하기 위한 메서드
///
/// Error Message
private void WriteExceptionLog(string msg)
{
if (UseExceptionLog)
ExceptionLog.Debug(_serialPort.PortName + " : " + msg);
}
#endregion
#region Property
///
/// lock 제어를 하기 위함.
///
private object thislock;
///
/// lock 제어를 하기 위함.
///
private bool lockcheck;
///
/// SerialPort와 직접 통신.
///
private SerialPort _serialPort;
///
/// SerialPort에서 받은 Data를 Encoding형식에 맞게 Parsing하기 위함.
///
public Encoding EncodeType { get { return encodeType; } private set { encodeType = value; } }
private Encoding encodeType;
///
/// Carriage Return ('\r')
///
public char CR { get { return '\r'; } }
///
/// Line Feed ('\n')
///
public char LF { get { return '\n'; } }
///
/// Splitter
///
public char Spliiter { get { return splitter; } private set { splitter = value; } }
private char splitter;
///
/// SerialPort의 Open 여부
///
public bool isOpen { get { return _serialPort.IsOpen; } }
///
/// Splitter로 Split하기 전 Data를 모아두는 저장소.
///
private List RecvData;
public bool cr_lf { get; set; }
#endregion
#region Construct
///
/// SerialPort를 생성하고 내부 Data를 설정하는 생성자.(Base Encoding은 ASCII)
///
/// Port이름 ex)COM6, COM13
/// 전송속도 ex)4800, 9600, 19200
/// Data의 마지막을 확인할 문자 기본 '\r'
/// 바이트 당 데이터 비트의 표준길이 ex)5, 6, 7, 8
/// 패리티 검사 프로토콜 ex)Ports.Parity.None
/// 비트당 정지비트의 표준 개수 ex)Ports.StopBits.One
/// 직렬 전송을 위한 핸드셰이킹 ex)Ports.Handshake.None
public Serial_Module(string PortName, int BaudRate, char Spliiter = '\n', int DataBits = 8, Parity Parity = Parity.None, StopBits StopBits = StopBits.One, Handshake Handshake = Handshake.None)
{
Create_Logger();
thislock = new object();
RecvData = new List();
_serialPort = new SerialPort();
_serialPort.PortName = PortName;
_serialPort.BaudRate = BaudRate;
_serialPort.DataBits = DataBits;
_serialPort.Parity = Parity;
_serialPort.StopBits = StopBits;
_serialPort.Handshake = Handshake;
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
this.Spliiter = Spliiter;
EncodeType = Encoding.ASCII;
}
///
/// SerialPort를 생성하고 내부 Data를 설정하는 생성자.(Base Encoding은 ASCII)
///
/// Port이름 ex)COM6, COM13
/// 전송속도 ex)4800, 9600, 19200
/// 바이트 당 데이터 비트의 표준길이 ex)5, 6, 7, 8
/// 패리티 검사 프로토콜 ex)Ports.Parity.None
/// 비트당 정지비트의 표준 개수 ex)Ports.StopBits.One
/// 직렬 전송을 위한 핸드셰이킹 ex)Ports.Handshake.None
public Serial_Module(string PortName, int BaudRate, int DataBits = 8, Parity Parity = Parity.None, StopBits StopBits = StopBits.One, Handshake Handshake = Handshake.None)
{
Create_Logger();
thislock = new object();
RecvData = new List();
_serialPort = new SerialPort();
_serialPort.PortName = PortName;
_serialPort.BaudRate = BaudRate;
_serialPort.DataBits = DataBits;
_serialPort.Parity = Parity;
_serialPort.StopBits = StopBits;
_serialPort.Handshake = Handshake;
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
this.Spliiter = '\n';
EncodeType = Encoding.ASCII;
}
#endregion
#region Fuction
///
/// Create Logger
///
private void Create_Logger()
{
Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
RollingFileAppender rollingAppender = new RollingFileAppender();
PatternLayout layout = new PatternLayout();
hierarchy.Configured = true;
rollingAppender.Name = "SerialExceptionRollingFile";
rollingAppender.LockingModel = new RollingFileAppender.MinimalLock();
rollingAppender.File = @"D:\Logger\Serial\Exception\";
rollingAppender.AppendToFile = true;
rollingAppender.DatePattern = "'SerialException'.yyyy-MM-dd.'log'";
rollingAppender.RollingStyle = RollingFileAppender.RollingMode.Composite;
rollingAppender.MaxSizeRollBackups = 10;
rollingAppender.MaximumFileSize = "100MB";
rollingAppender.StaticLogFileName = false;
rollingAppender.Encoding = System.Text.Encoding.UTF8;
layout = new PatternLayout("%d{yyyy/MM/dd,HH:mm:ss.fff,} %m%n");
layout.ActivateOptions();
rollingAppender.Layout = layout;
rollingAppender.ActivateOptions();
hierarchy.GetLogger("SerialException");
ILog log = LogManager.GetLogger("SerialException");
Logger l = (Logger)log.Logger;
l.Level = log4net.Core.Level.Debug;
l.AddAppender(rollingAppender);
ExceptionLog = LogManager.GetLogger("SerialException");
}
///
/// encodeType을 설정해주는 메서드
///
///
public void SetEncodeType(Encoding encodeType)
{
this.EncodeType = encodeType;
}
///
/// 사용가능한 Portname을 반환.
///
/// Portname 값
public static string[] GetPorts()
{
return SerialPort.GetPortNames();
}
///
/// 설정 Port Open
///
/// 성공 실패 여부
public bool Open()
{
try
{
_serialPort.Open();
return true;
}
catch (Exception ex)
{
WriteExceptionLog(MethodBase.GetCurrentMethod().Name + " : " + ex.Message);
return false;
}
}
///
/// 설정 Port Close
///
/// 성공 실패 여부
public bool Close()
{
try
{
_serialPort.Close();
return true;
}
catch (Exception ex)
{
WriteExceptionLog(MethodBase.GetCurrentMethod().Name + " : " + ex.Message);
return false;
}
}
///
/// SerialPort에 Data를 보내기 위한 메서드
///
/// string형 Data
///
public bool SendData(string sCmd)
{
try
{
lock (thislock)
{
while (lockcheck)
Monitor.Wait(thislock);
lockcheck = true;
if (cr_lf)
{
_serialPort.Write(sCmd + CR + LF);
}
else
{
_serialPort.Write(sCmd);
}
lockcheck = false;
Monitor.Pulse(thislock);
}
return true;
}
catch (Exception ex)
{
WriteExceptionLog(MethodBase.GetCurrentMethod().Name + " : " + ex.Message);
lockcheck = false;
return false;
}
}
///
/// SerialPort에 Data를 보내기 위한 메서드
///
/// byte형 배열 Data
///
public bool SendData(byte[] bCmd)
{
try
{
lock (thislock)
{
while (lockcheck)
Monitor.Wait(thislock);
lockcheck = true;
_serialPort.Write(bCmd, 0, bCmd.Length);
lockcheck = false;
Monitor.Pulse(thislock);
}
return true;
}
catch (Exception ex)
{
WriteExceptionLog(MethodBase.GetCurrentMethod().Name + " : " + ex.Message);
lockcheck = false;
return false;
}
}
///
/// SerialPort에 Data를 보내기 위한 메서드
///
/// char형 배열 Data
///
public bool SendData(char[] cCmd)
{
try
{
lock (thislock)
{
while (lockcheck)
Monitor.Wait(thislock);
lockcheck = true;
_serialPort.Write(cCmd, 0, cCmd.Length);
lockcheck = false;
Monitor.Pulse(thislock);
}
return true;
}
catch (Exception ex)
{
WriteExceptionLog(MethodBase.GetCurrentMethod().Name + " : " + ex.Message);
lockcheck = false;
return false;
}
}
///
/// SerialPort에서 Data를 읽기 위한 메서드
///
///
public byte[] ReadData()
{
try
{
byte[] recvbyte;
lock (thislock)
{
while (lockcheck)
Monitor.Wait(thislock);
lockcheck = true;
RecvData.Clear();
DateTime check = DateTime.Now;
while (true)
{
if (_serialPort.BytesToRead > 0)
{
if (CheckData((byte)_serialPort.ReadByte()))
{
break;
}
}
if ((DateTime.Now - check).TotalMilliseconds > _serialPort.ReadTimeout)
{
throw new TimeoutException("Serial Receieve Timeout");
}
}
recvbyte = RecvData.ToArray();
lockcheck = false;
Monitor.Pulse(thislock);
}
return recvbyte;
}
catch (Exception ex)
{
WriteExceptionLog(MethodBase.GetCurrentMethod().Name + " : " + ex.Message);
lockcheck = false;
return null;
}
}
///
/// SerialPort에 Data를 보낸후 Read 대기
///
/// string Data
///
public byte[] SendWaitData(string sCmd)
{
try
{
byte[] recvbyte;
lock (thislock)
{
while (lockcheck)
Monitor.Wait(thislock);
lockcheck = true;
if (_serialPort.BytesToRead > 0) _serialPort.ReadExisting();
_serialPort.BaseStream.Flush();
if (cr_lf)
{
_serialPort.Write(sCmd + CR + LF);
}
else
{
_serialPort.Write(sCmd);
}
RecvData.Clear();
DateTime check = DateTime.Now;
while (true)
{
if (_serialPort.BytesToRead > 0)
{
if (CheckData((byte)_serialPort.ReadByte()))
{
break;
}
}
if ((DateTime.Now - check).TotalMilliseconds > _serialPort.ReadTimeout)
{
throw new TimeoutException("Serial Receieve Timeout");
}
}
recvbyte = RecvData.ToArray();
lockcheck = false;
Monitor.Pulse(thislock);
}
return recvbyte;
}
catch (Exception ex)
{
WriteExceptionLog(MethodBase.GetCurrentMethod().Name + " : " + ex.Message);
lockcheck = false;
return null;
}
}
///
/// SerialPort에 Data를 보낸후 Read 대기
///
/// byte형 배열 Data
///
public byte[] SendWaitData(byte[] bCmd)
{
try
{
byte[] recvbyte;
lock (thislock)
{
while (lockcheck)
Monitor.Wait(thislock);
lockcheck = true;
if (_serialPort.BytesToRead > 0) _serialPort.ReadExisting();
_serialPort.BaseStream.Flush();
_serialPort.Write(bCmd, 0, bCmd.Length);
RecvData.Clear();
DateTime check = DateTime.Now;
while (true)
{
if (_serialPort.BytesToRead > 0)
{
if (CheckData((byte)_serialPort.ReadByte()))
{
break;
}
}
if ((DateTime.Now - check).TotalMilliseconds > _serialPort.ReadTimeout)
{
throw new TimeoutException("Serial Receieve Timeout");
}
}
recvbyte = RecvData.ToArray();
lockcheck = false;
Monitor.Pulse(thislock);
}
return recvbyte;
}
catch (Exception ex)
{
WriteExceptionLog(MethodBase.GetCurrentMethod().Name + " : " + ex.Message);
lockcheck = false;
return null;
}
}
///
/// SerialPort에 Data를 보낸후 Read 대기
///
/// char형 배열 Data
///
public byte[] SendWaitData(char[] cCmd)
{
try
{
byte[] recvbyte;
lock (thislock)
{
while (lockcheck)
Monitor.Wait(thislock);
lockcheck = true;
if (_serialPort.BytesToRead > 0) _serialPort.ReadExisting();
_serialPort.BaseStream.Flush();
_serialPort.Write(cCmd, 0, cCmd.Length);
RecvData.Clear();
DateTime check = DateTime.Now;
while (true)
{
if (_serialPort.BytesToRead > 0)
{
if (CheckData((byte)_serialPort.ReadByte()))
{
break;
}
}
if ((DateTime.Now - check).TotalMilliseconds > _serialPort.ReadTimeout)
{
throw new TimeoutException("Serial Receieve Timeout");
}
}
recvbyte = RecvData.ToArray();
lockcheck = false;
Monitor.Pulse(thislock);
}
return recvbyte;
}
catch (Exception ex)
{
WriteExceptionLog(MethodBase.GetCurrentMethod().Name + " : " + ex.Message);
lockcheck = false;
return null;
}
}
///
/// Splitter Data의 유무를 판별하기 위한 메서드
///
/// SerialPort에서 받은 Data
///
private bool CheckData(byte bytes)
{
try
{
RecvData.Add(bytes);
if (bytes == Spliiter)
return true;
else
return false;
}
catch (Exception ex)
{
WriteExceptionLog(MethodBase.GetCurrentMethod().Name + " : " + ex.Message);
return false;
}
}
#endregion
}
}