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 } }