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
|
{
|
|
/// <summary>
|
/// Serial Module을 제어하기 위한 클래스
|
/// </summary>
|
public class Serial_Module
|
{
|
#region Enum
|
#endregion
|
|
#region Logger
|
/// <summary>
|
/// Exception Log
|
/// </summary>
|
private ILog ExceptionLog = LogManager.GetLogger("SerialException");
|
|
/// <summary>
|
/// Exception Log 사용유무 확인
|
/// </summary>
|
public bool UseExceptionLog { get; set; }
|
|
/// <summary>
|
/// Exception Log를 기록하기 위한 메서드
|
/// </summary>
|
/// <param name="msg">Error Message</param>
|
private void WriteExceptionLog(string msg)
|
{
|
if (UseExceptionLog)
|
ExceptionLog.Debug(_serialPort.PortName + " : " + msg);
|
}
|
#endregion
|
|
#region Property
|
/// <summary>
|
/// lock 제어를 하기 위함.
|
/// </summary>
|
private object thislock;
|
|
/// <summary>
|
/// lock 제어를 하기 위함.
|
/// </summary>
|
private bool lockcheck;
|
|
/// <summary>
|
/// SerialPort와 직접 통신.
|
/// </summary>
|
private SerialPort _serialPort;
|
|
/// <summary>
|
/// SerialPort에서 받은 Data를 Encoding형식에 맞게 Parsing하기 위함.
|
/// </summary>
|
public Encoding EncodeType { get { return encodeType; } private set { encodeType = value; } }
|
private Encoding encodeType;
|
|
/// <summary>
|
/// Carriage Return ('\r')
|
/// </summary>
|
public char CR { get { return '\r'; } }
|
|
/// <summary>
|
/// Line Feed ('\n')
|
/// </summary>
|
public char LF { get { return '\n'; } }
|
|
/// <summary>
|
/// Splitter
|
/// </summary>
|
public char Spliiter { get { return splitter; } private set { splitter = value; } }
|
private char splitter;
|
|
/// <summary>
|
/// SerialPort의 Open 여부
|
/// </summary>
|
public bool isOpen { get { return _serialPort.IsOpen; } }
|
|
/// <summary>
|
/// Splitter로 Split하기 전 Data를 모아두는 저장소.
|
/// </summary>
|
private List<byte> RecvData;
|
|
public bool cr_lf { get; set; }
|
#endregion
|
|
#region Construct
|
/// <summary>
|
/// SerialPort를 생성하고 내부 Data를 설정하는 생성자.(Base Encoding은 ASCII)
|
/// </summary>
|
/// <param name="PortName"> Port이름 ex)COM6, COM13 </param>
|
/// <param name="BaudRate"> 전송속도 ex)4800, 9600, 19200 </param>
|
/// <param name="Spliiter"> Data의 마지막을 확인할 문자 기본 '\r' </param>
|
/// <param name="DataBits"> 바이트 당 데이터 비트의 표준길이 ex)5, 6, 7, 8 </param>
|
/// <param name="Parity">패리티 검사 프로토콜 ex)Ports.Parity.None </param>
|
/// <param name="StopBits">비트당 정지비트의 표준 개수 ex)Ports.StopBits.One </param>
|
/// <param name="Handshake">직렬 전송을 위한 핸드셰이킹 ex)Ports.Handshake.None</param>
|
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<byte>();
|
_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;
|
}
|
|
/// <summary>
|
/// SerialPort를 생성하고 내부 Data를 설정하는 생성자.(Base Encoding은 ASCII)
|
/// </summary>
|
/// <param name="PortName"> Port이름 ex)COM6, COM13 </param>
|
/// <param name="BaudRate"> 전송속도 ex)4800, 9600, 19200 </param>
|
/// <param name="DataBits"> 바이트 당 데이터 비트의 표준길이 ex)5, 6, 7, 8 </param>
|
/// <param name="Parity">패리티 검사 프로토콜 ex)Ports.Parity.None </param>
|
/// <param name="StopBits">비트당 정지비트의 표준 개수 ex)Ports.StopBits.One </param>
|
/// <param name="Handshake">직렬 전송을 위한 핸드셰이킹 ex)Ports.Handshake.None</param>
|
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<byte>();
|
_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
|
|
/// <summary>
|
/// Create Logger
|
/// </summary>
|
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");
|
}
|
|
/// <summary>
|
/// encodeType을 설정해주는 메서드
|
/// </summary>
|
/// <param name="encodeType"></param>
|
public void SetEncodeType(Encoding encodeType)
|
{
|
this.EncodeType = encodeType;
|
}
|
|
/// <summary>
|
/// 사용가능한 Portname을 반환.
|
/// </summary>
|
/// <returns>Portname 값</returns>
|
public static string[] GetPorts()
|
{
|
return SerialPort.GetPortNames();
|
}
|
|
/// <summary>
|
/// 설정 Port Open
|
/// </summary>
|
/// <returns>성공 실패 여부</returns>
|
public bool Open()
|
{
|
try
|
{
|
_serialPort.Open();
|
return true;
|
}
|
catch (Exception ex)
|
{
|
WriteExceptionLog(MethodBase.GetCurrentMethod().Name + " : " + ex.Message);
|
return false;
|
}
|
}
|
|
/// <summary>
|
/// 설정 Port Close
|
/// </summary>
|
/// <returns>성공 실패 여부</returns>
|
public bool Close()
|
{
|
try
|
{
|
_serialPort.Close();
|
return true;
|
}
|
catch (Exception ex)
|
{
|
WriteExceptionLog(MethodBase.GetCurrentMethod().Name + " : " + ex.Message);
|
return false;
|
}
|
}
|
|
/// <summary>
|
/// SerialPort에 Data를 보내기 위한 메서드
|
/// </summary>
|
/// <param name="sCmd">string형 Data</param>
|
/// <returns></returns>
|
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;
|
}
|
}
|
|
/// <summary>
|
/// SerialPort에 Data를 보내기 위한 메서드
|
/// </summary>
|
/// <param name="bCmd">byte형 배열 Data</param>
|
/// <returns></returns>
|
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;
|
}
|
}
|
|
/// <summary>
|
/// SerialPort에 Data를 보내기 위한 메서드
|
/// </summary>
|
/// <param name="cCmd">char형 배열 Data</param>
|
/// <returns></returns>
|
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;
|
}
|
}
|
|
/// <summary>
|
/// SerialPort에서 Data를 읽기 위한 메서드
|
/// </summary>
|
/// <returns></returns>
|
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;
|
}
|
}
|
|
/// <summary>
|
/// SerialPort에 Data를 보낸후 Read 대기
|
/// </summary>
|
/// <param name="sCmd">string Data</param>
|
/// <returns></returns>
|
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;
|
}
|
}
|
|
/// <summary>
|
/// SerialPort에 Data를 보낸후 Read 대기
|
/// </summary>
|
/// <param name="bCmd">byte형 배열 Data</param>
|
/// <returns></returns>
|
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;
|
}
|
}
|
|
/// <summary>
|
/// SerialPort에 Data를 보낸후 Read 대기
|
/// </summary>
|
/// <param name="cCmd">char형 배열 Data</param>
|
/// <returns></returns>
|
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;
|
}
|
}
|
|
/// <summary>
|
/// Splitter Data의 유무를 판별하기 위한 메서드
|
/// </summary>
|
/// <param name="bytes">SerialPort에서 받은 Data</param>
|
/// <returns></returns>
|
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
|
}
|
}
|