1175 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			1175 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Linq;
 | |
| using System.Text;
 | |
| using System.ComponentModel;
 | |
| using System.Threading;
 | |
| 
 | |
| namespace arDev
 | |
| {
 | |
| 	public class RS232 : IDisposable
 | |
| 	{
 | |
| 		protected Boolean _isinit = false;
 | |
| 
 | |
| 		#region "Event Args"
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 데이터를 수신할떄 사용함(RAW 포함)
 | |
| 		/// </summary>
 | |
| 		public class ReceiveDataEventArgs : EventArgs
 | |
| 		{
 | |
| 			private readonly byte[] _buffer = null;
 | |
| 
 | |
| 			/// <summary>
 | |
| 			/// 바이트배열의 버퍼값
 | |
| 			/// </summary>
 | |
| 			public byte[] Value { get { return _buffer; } }
 | |
| 
 | |
| 			/// <summary>
 | |
| 			/// 버퍼(바이트배열)의 데이터를 문자로 반환합니다.
 | |
| 			/// </summary>
 | |
| 			public string StrValue
 | |
| 			{
 | |
| 				get
 | |
| 				{
 | |
| 					//return string.Empty; 
 | |
| 
 | |
| 					if (_buffer == null || _buffer.Length < 1) return string.Empty;
 | |
| 					else return System.Text.Encoding.Default.GetString(_buffer);
 | |
| 				}
 | |
| 			}
 | |
| 			public ReceiveDataEventArgs(byte[] buffer)
 | |
| 			{
 | |
| 				_buffer = buffer;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public class MessageEventArgs : EventArgs
 | |
| 		{
 | |
| 			private readonly Boolean _isError = false;
 | |
| 			public Boolean IsError { get { return _isError; } }
 | |
| 			private readonly string _message = string.Empty;
 | |
| 			public string Message { get { return _message; } }
 | |
| 			public MessageEventArgs(Boolean isError, string Message)
 | |
| 			{
 | |
| 				_isError = isError;
 | |
| 				_message = Message;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region "Enum & Structure"
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 데이터수신시 해당 데이터의 끝을 결정하는 방식을 설정합니다.
 | |
| 		/// </summary>
 | |
| 		public enum eTerminal : byte
 | |
| 		{
 | |
| 			/// <summary>
 | |
| 			/// line feed
 | |
| 			/// </summary>
 | |
| 			LF = 0,
 | |
| 
 | |
| 			/// <summary>
 | |
| 			/// carrige return
 | |
| 			/// </summary>
 | |
| 			CR,
 | |
| 
 | |
| 			/// <summary>
 | |
| 			/// cr+lf
 | |
| 			/// </summary>
 | |
| 			CRLF,
 | |
| 
 | |
| 			/// <summary>
 | |
| 			/// stx +  ETx 구성된 프로토콜을 감지합니다. stx,etx는 임의 지정이 가능하며 기본값으로는 stx = 0x02, etx = 0x03 을 가지고 있습니다.
 | |
| 			/// </summary>
 | |
| 			ETX,
 | |
| 
 | |
| 			/// <summary>
 | |
| 			/// 데이터의 길이를 가지고 판단합니다.
 | |
| 			/// </summary>
 | |
| 			Length,
 | |
| 
 | |
| 			/// <summary>
 | |
| 			/// 설정없음 .. 일정시간동안 대기한 후 버퍼의 내용을 모두 데이터로 인정합니다.
 | |
| 			/// </summary>
 | |
| 			None,
 | |
| 
 | |
| 			/// <summary>
 | |
| 			/// 내부 Receive 이벤트를 사용하지 않고 Raw 이벤트를 사용합니다.
 | |
| 			/// 이 값을 설정할 경우 내부 Receivce 이벤트 내에서 메세지 수신 이벤트가 발생하지 않습니다.
 | |
| 			/// DataParSER을 상속하여 해당 파서에서 데이터를 분리하세요. True 이면 분리성공, false 이면 완료될때까지 대기합니다.
 | |
| 			/// </summary>
 | |
| 			CustomParser
 | |
| 		}
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region "Public variable"
 | |
| 		/// <summary>
 | |
| 		/// WriteDataSync 명령 사용시 최대로 기다리는 시간
 | |
| 		/// </summary>
 | |
| 		public int syncTimeout = 5000;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 오류가 발생했다면 이 변수에 그 내용이 기록됩니다.
 | |
| 		/// </summary>
 | |
| 		public string errorMessage = string.Empty;
 | |
| 
 | |
| 		///// <summary>
 | |
| 		///// WriteDataSync 명령 사용시 최대로 기다리는 시간
 | |
| 		///// </summary>
 | |
| 		//public int syncTimeout = 5000;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 이 값은 종단기호 형식이 Length 일때 사용됩니다. 버퍼의 갯수이 이 값과 일치하면 수신 이벤트를 발생합니다.
 | |
| 		/// </summary>
 | |
| 		public int MaxDataLength = 0x0d;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 마지막으로 데이터는 전송한 시간
 | |
| 		/// </summary>
 | |
| 		public DateTime lastSendTime;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 최종 전송 메세지
 | |
| 		/// </summary>
 | |
| 		public byte[] lastSendBuffer;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 마지막으로 데이터를 받은 시간
 | |
| 		/// </summary>
 | |
| 		public DateTime lastRecvTime = DateTime.Parse("1982-11-23");
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 데이터 전송시 전송메세지를 발생할것인가? 171113
 | |
| 		/// </summary>
 | |
| 		public Boolean EnableTxMessage { get; set; }
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// terminal 이 stx 일때에만 사용하며 기본값은 0x03
 | |
| 		/// </summary>
 | |
| 		[Description("종단기호형식이 ETX일때 사용하는 데이터의 종료문자값입니다. 바이트값이므로 0~255 사이로 입력하세요.")]
 | |
| 		[Category("설정"), DisplayName("Data End Byte")]
 | |
| 		public byte ETX { get; set; }
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region "Protect & private Variable"
 | |
| 
 | |
| 		protected Boolean CheckACK { get; set; }
 | |
| 		protected Boolean CheckNAK { get; set; }
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 메세지 수신시 사용하는 내부버퍼
 | |
| 		/// </summary>
 | |
| 		protected List<byte> _buffer = new List<byte>();
 | |
| 
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 데이터의 끝을 분석하는 종단기호의 설정
 | |
| 		/// </summary>
 | |
| 		private eTerminal _term = eTerminal.LF;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// WriteDataSync 명령사용시 활성화됨
 | |
| 		/// </summary>
 | |
| 		protected Boolean _isSync = false;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// sync timeOUt체크시 사용합니다.
 | |
| 		/// </summary>
 | |
| 		private System.Diagnostics.Stopwatch _wat = new System.Diagnostics.Stopwatch();
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Serialport Device
 | |
| 		/// </summary>
 | |
| 		protected System.IO.Ports.SerialPort _device;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// for autoreset events
 | |
| 		/// </summary>
 | |
| 		protected ManualResetEvent _mre;
 | |
| 
 | |
| 		protected Boolean isDisposed = false;
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region "Internal Events"
 | |
| 
 | |
| 		void barcode_ErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
 | |
| 		{
 | |
| 			if (Message != null) Message(this, new MessageEventArgs(true, e.ToString()));
 | |
| 		}
 | |
| 
 | |
| 		void barcode_PinChanged(object sender, System.IO.Ports.SerialPinChangedEventArgs e)
 | |
| 		{
 | |
| 
 | |
| 			if (serialPinchanged != null)
 | |
| 				serialPinchanged(this, e);
 | |
| 			//if (Message != null) Message(this, new MessageEventArgs(true, "PinChanged"));
 | |
| 		}
 | |
| 
 | |
| 		void barcode_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
 | |
| 		{
 | |
| 			this.lastRecvTime = DateTime.Now;
 | |
| 
 | |
| 			if (_isSync) return; //싱크모드일경우에는 해당 루틴에서 직접 읽는다
 | |
| 			_isSync = false;
 | |
| 			//none일경우에는 100ms 정도 기다려준다.
 | |
| 			if (_term == eTerminal.None)
 | |
| 			{
 | |
| 				//none 일경우에는 무조건 데이터로 취급한다.
 | |
| 				System.Threading.Thread.Sleep(200);
 | |
| 				_buffer.Clear();
 | |
| 			}
 | |
| 
 | |
| 			try
 | |
| 			{
 | |
| 				int ReadCount = _device.BytesToRead;
 | |
| 
 | |
| 				byte[] buffer = new byte[ReadCount];
 | |
| 				_device.Read(buffer, 0, buffer.Length);
 | |
| 
 | |
| 				if (ReceiveData_Raw != null) ReceiveData_Raw(this, new ReceiveDataEventArgs(buffer));
 | |
| 				System.Text.StringBuilder LogMsg = new StringBuilder();
 | |
| 
 | |
| 				if (Terminal == eTerminal.CustomParser)
 | |
| 				{
 | |
| 					byte[] remainBuffer;
 | |
| 				Repeat:
 | |
| 					if (CustomParser(buffer, out remainBuffer))
 | |
| 					{
 | |
| 						//parser ok
 | |
| 						RaiseRecvData(_buffer.ToArray());
 | |
| 						_buffer.Clear();
 | |
| 						if (remainBuffer != null && remainBuffer.Length > 0)
 | |
| 						{
 | |
| 							//버퍼를 변경해서 다시 전송을 해준다.
 | |
| 							buffer = new byte[remainBuffer.Length];
 | |
| 							Array.Copy(remainBuffer, buffer, buffer.Length);
 | |
| 							goto Repeat; //남은 버퍼가 있다면 진행을 해준다.
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					foreach (byte bb in buffer)
 | |
| 					{
 | |
| 						switch (_term)
 | |
| 						{
 | |
| 
 | |
| 							case eTerminal.CR:
 | |
| 								if (bb == 0x0D)
 | |
| 								{
 | |
| 									RaiseRecvData(_buffer.ToArray()); ;
 | |
| 									_buffer.Clear();
 | |
| 								}
 | |
| 								else _buffer.Add(bb);
 | |
| 								break;
 | |
| 							case eTerminal.LF:
 | |
| 								if (bb == 0x0A)
 | |
| 								{
 | |
| 									RaiseRecvData(_buffer.ToArray()); ;
 | |
| 									_buffer.Clear();
 | |
| 								}
 | |
| 								else _buffer.Add(bb);
 | |
| 								break;
 | |
| 							case eTerminal.CRLF:
 | |
| 								if (bb == 0x0A)
 | |
| 								{
 | |
| 									RaiseRecvData(_buffer.ToArray()); ;
 | |
| 									_buffer.Clear();
 | |
| 								}
 | |
| 								else if (bb == 0x0D)
 | |
| 								{
 | |
| 									//0d는 그냥 넘어간다.
 | |
| 								}
 | |
| 								else _buffer.Add(bb);
 | |
| 								break;
 | |
| 							case eTerminal.Length:
 | |
| 								_buffer.Add(bb);
 | |
| 								if (_buffer.Count == MaxDataLength)
 | |
| 								{
 | |
| 									RaiseRecvData(_buffer.ToArray()); ;
 | |
| 									_buffer.Clear();
 | |
| 								}
 | |
| 								else if (_buffer.Count > MaxDataLength)
 | |
| 								{
 | |
| 									RaiseMessage("Buffer Length Error " + _buffer.Count.ToString() + "/" + MaxDataLength.ToString(), true);
 | |
| 									_buffer.Clear();
 | |
| 								}
 | |
| 								break;
 | |
| 							case eTerminal.ETX: //asc타입의 프로토콜에서는 STX,ETX가 고유값이다.
 | |
| 								if (bb == STX)
 | |
| 								{
 | |
| 									_buffer.Clear();
 | |
| 								}
 | |
| 								else if (bb == ETX)
 | |
| 								{
 | |
| 									RaiseRecvData(_buffer.ToArray()); ;
 | |
| 									_buffer.Clear();
 | |
| 								}
 | |
| 								else _buffer.Add(bb);
 | |
| 								break;
 | |
| 							case eTerminal.None:
 | |
| 								_buffer.Add(bb);
 | |
| 								break;
 | |
| 						}
 | |
| 					}
 | |
| 
 | |
| 					//170802
 | |
| 					if (_term == eTerminal.None)
 | |
| 					{
 | |
| 						RaiseRecvData(_buffer.ToArray()); ;
 | |
| 						_buffer.Clear();
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			catch (Exception ex)
 | |
| 			{
 | |
| 				if (IsOpen())
 | |
| 				{
 | |
| 					//_device.DiscardInBuffer();
 | |
| 					//_device.DiscardOutBuffer();
 | |
| 				}
 | |
| 				errorMessage = ex.Message;
 | |
| 				RaiseMessage(ex.Message, true);
 | |
| 			}
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region "External Events"
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 바코드에서 들어오는 데이터의 원본 메세지
 | |
| 		/// </summary>
 | |
| 		public event EventHandler<ReceiveDataEventArgs> ReceiveData_Raw;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 데이터가 들어올 경우 발생합니다 (종단기호=Termianl) 문자열이 발견된 후에 발생함
 | |
| 		/// </summary>
 | |
| 		public event EventHandler<ReceiveDataEventArgs> ReceiveData;
 | |
| 
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 데이터를 전송할 때 해당 이벤트가 발생합니다.
 | |
| 		/// </summary>
 | |
| 		public event EventHandler<ReceiveDataEventArgs> SendData;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 오류 및 기타 일반 메세지
 | |
| 		/// </summary>
 | |
| 		public event EventHandler<MessageEventArgs> Message;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 시리얼포트의 핀 상태값이 변경될 때 발생합니다.
 | |
| 		/// </summary>
 | |
| 		public event EventHandler<System.IO.Ports.SerialPinChangedEventArgs> serialPinchanged;
 | |
| 
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region "Properties"
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 식별번호(임의지정가능) - 장치 생성시 입력
 | |
| 		/// </summary>
 | |
| 		[Description("이 장치의 식별 ID(임의 지정가능)")]
 | |
| 		[Category("설정"), DisplayName("Device No")]
 | |
| 		public string Tag { get; set; }
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// terminal 이 etx 일때에만 사용하며 기본값은 0x02
 | |
| 		/// </summary>
 | |
| 		[Description("종단기호형식이 ETX일때 사용하는 데이터의 시작문자값입니다. 바이트값이므로 0~255 사이로 입력하세요.")]
 | |
| 		[Category("설정"), DisplayName("Data Start Byte")]
 | |
| 		public byte STX { get; set; }
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 내장 분석기(Parser)를 사용할 경우 최종 데이터에서 CR,LF를 제거할지 선택합니다.
 | |
| 		/// </summary>
 | |
| 		[Description("내장분석기(Parser)를 사용할 경우 최종 데이터에서 CR.LF를 제거할지 선택합니다.")]
 | |
| 		[Category("기타"), DisplayName("CRLF 제거")]
 | |
| 		public Boolean RemoveCRLFNULL { get; set; }
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 종단기호 형식
 | |
| 		/// </summary>
 | |
| 		[Description("데이터의 종단기호를 설정합니다. 지정한 데이터가 올경우")]
 | |
| 		[Category("설정"), DisplayName("종단기호")]
 | |
| 		public eTerminal Terminal { get { return _term; } set { _term = value; } }
 | |
| 
 | |
| 		[Category("설정")]
 | |
| 		public System.IO.Ports.Parity Parity
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 
 | |
| 				return _device.Parity;
 | |
| 			}
 | |
| 			set
 | |
| 			{
 | |
| 				_device.Parity = value;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		[Category("설정")]
 | |
| 		public int DataBits
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				return _device.DataBits;
 | |
| 			}
 | |
| 			set
 | |
| 			{
 | |
| 				_device.DataBits = value;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		[Category("설정")]
 | |
| 		public System.IO.Ports.StopBits StopBits
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				return _device.StopBits;
 | |
| 			}
 | |
| 			set
 | |
| 			{
 | |
| 				_device.StopBits = value;
 | |
| 			}
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 		[Category("설정")]
 | |
| 		public System.IO.Ports.Handshake Handshake
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				return _device.Handshake;
 | |
| 			}
 | |
| 			set
 | |
| 			{
 | |
| 				_device.Handshake = value;
 | |
| 			}
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 		#region "pin state & pin setting"
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Data Terminal Ready
 | |
| 		/// </summary>
 | |
| 		[Description("Data Terminal Ready 신호의 사용여부")]
 | |
| 		[Category("PIN")]
 | |
| 		public Boolean DtrEnable
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				return _device.DtrEnable;
 | |
| 
 | |
| 			}
 | |
| 			set
 | |
| 			{
 | |
| 				_device.DtrEnable = value;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Request To Send
 | |
| 		/// </summary>
 | |
| 		[Description("Request to Send 신호의 사용여부")]
 | |
| 		[Category("PIN")]
 | |
| 		public Boolean RtsEnable
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				return _device.RtsEnable;
 | |
| 
 | |
| 			}
 | |
| 			set
 | |
| 			{
 | |
| 				_device.RtsEnable = value;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Data set Ready 신호 상태
 | |
| 		/// </summary>
 | |
| 		[Description("Data Set Ready 신호 상태")]
 | |
| 		[Category("PIN")]
 | |
| 		public Boolean PIN_DSR
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				if (!IsOpen()) return false;
 | |
| 				return _device.DsrHolding;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Carrier Detect
 | |
| 		/// </summary>
 | |
| 		[Description("Carrier Detect 신호 상태")]
 | |
| 		[Category("PIN")]
 | |
| 		public Boolean PIN_CD
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				if (!IsOpen()) return false;
 | |
| 				return _device.CDHolding;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Clear to Send
 | |
| 		/// </summary>
 | |
| 		[Description("Clear to Send 신호 상태")]
 | |
| 		[Category("PIN")]
 | |
| 		public Boolean PIN_CTS
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				if (!IsOpen()) return false;
 | |
| 				return _device.CtsHolding;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Break State
 | |
| 		/// </summary>
 | |
| 		[Description("중단신호 상태")]
 | |
| 		[Category("PIN")]
 | |
| 		public Boolean PIN_BreakState
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				if (!IsOpen()) return false;
 | |
| 				return _device.BreakState;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 포트가 열려있는지 확인
 | |
| 		/// </summary>
 | |
| 		[Description("현재 시리얼포트가 열려있는지 확인합니다")]
 | |
| 		[Category("정보"), DisplayName("Port Open")]
 | |
| 		public virtual Boolean IsOpen()
 | |
| 		{
 | |
| 			if (_device == null) return false;
 | |
| 			return _device.IsOpen;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 초기화등이 성공했는지 확인합니다.close 되었다면 실패입니다. isinit 변수값을 적절히 수정하시기 바랍니다.
 | |
| 		/// </summary>
 | |
| 		[Description("초기화성공여부 별도의 초기화 코드가없다면 isOpen 과 동일합니다.")]
 | |
| 		[Category("정보"), DisplayName("Init OK?")]
 | |
| 		public virtual Boolean IsInit()
 | |
| 		{
 | |
| 
 | |
| 			if (!IsOpen() || !_isinit) return false;
 | |
| 			return true;
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 쓰기타임아웃
 | |
| 		/// </summary>
 | |
| 		[Description("쓰기명령어의 최대대기시간(단위:ms)\r\n지정 시간을 초과할 경우 오류가 발생합니다.")]
 | |
| 		[Category("설정"), DisplayName("쓰기 제한시간")]
 | |
| 		public int WriteTimeout
 | |
| 		{
 | |
| 			get { return _device.WriteTimeout; }
 | |
| 			set { _device.WriteTimeout = value; }
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 읽기타임아웃
 | |
| 		/// </summary>
 | |
| 		[Description("읽기명령어의 최대대기시간(단위:ms)\r\n지정 시간을 초과할 경우 오류가 발생합니다.")]
 | |
| 		[Category("설정"), DisplayName("읽기 제한시간")]
 | |
| 		public int ReadTimeout
 | |
| 		{
 | |
| 			get { return _device.ReadTimeout; }
 | |
| 			set { _device.ReadTimeout = value; }
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 포트이름
 | |
| 		/// </summary>
 | |
| 		[Description("시리얼 포트 이름")]
 | |
| 		[Category("설정"), DisplayName("Port Name")]
 | |
| 		public string PortName { get { return _device.PortName; } set { if (string.IsNullOrEmpty(value) == false) _device.PortName = value; } }
 | |
| 		/// <summary>
 | |
| 		/// RS232 Baud Rate
 | |
| 		/// </summary>
 | |
| 		[Description("시리얼 포트 전송 속도")]
 | |
| 		[Category("설정"), DisplayName("Baud Rate")]
 | |
| 		public int BaudRate { get { return _device.BaudRate; } set { _device.BaudRate = value; } }
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region "Method"
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 쓰기버퍼비우기
 | |
| 		/// </summary>
 | |
| 		public void ClearWriteBuffer()
 | |
| 		{
 | |
| 			if (_device.IsOpen) _device.DiscardOutBuffer();
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 읽기버퍼비우기
 | |
| 		/// </summary>
 | |
| 		public void ClearReadBuffer()
 | |
| 		{
 | |
| 			if (_device.IsOpen) _device.DiscardInBuffer();
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 장치의 초기화작업을 수행합니다.(이 값은 기본값으로 true가 무조건 설정됩니다) 오버라이드하여 각 상황에 맞게 처리하세요.
 | |
| 		/// </summary>
 | |
| 		protected virtual void Init()
 | |
| 		{
 | |
| 			if (!IsOpen()) _isinit = false;
 | |
| 			else _isinit = true;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		protected virtual Boolean CustomParser(byte[] buf, out byte[] remainBuffer)
 | |
| 		{
 | |
| 			remainBuffer = new byte[] { };
 | |
| 			return true;
 | |
| 		}
 | |
| 
 | |
| 		#region "Raise Message Events (임의로 메세지를 발생시킵니다)"
 | |
| 
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 보낸메세지 이벤트를 발생
 | |
| 		/// </summary>
 | |
| 		/// <param name="data">String Data</param>
 | |
| 		public void RaiseSendData(string data)
 | |
| 		{
 | |
| 			RaiseSendData(System.Text.Encoding.Default.GetBytes(data));
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 보낸메세지 이벤트를 발생 합니다.
 | |
| 		/// </summary>
 | |
| 		/// <param name="data">Byte Array</param>
 | |
| 		public void RaiseSendData(byte[] data)
 | |
| 		{
 | |
| 			try
 | |
| 			{
 | |
| 				if (SendData != null) SendData(this, new ReceiveDataEventArgs(data));
 | |
| 			}
 | |
| 			catch (Exception ex)
 | |
| 			{
 | |
| 				RaiseMessage("RaiseSendData:" + ex.Message, true);
 | |
| 			}
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 지정한 데이터로 바코드가 수신된것처럼 발생시킵니다.
 | |
| 		/// </summary>
 | |
| 		/// <param name="b"></param>
 | |
| 		public void RaiseRecvData(byte[] b)
 | |
| 		{
 | |
| 			byte[] Data;
 | |
| 
 | |
| 			if (RemoveCRLFNULL) //제거해야하는경우에만 처리 170822
 | |
| 				Data = RemoveCRLF(b);
 | |
| 			else
 | |
| 				Data = b;
 | |
| 
 | |
| 			try
 | |
| 			{
 | |
| 				if (ReceiveData != null) ReceiveData(this, new ReceiveDataEventArgs(Data));
 | |
| 			}
 | |
| 			catch (Exception ex)
 | |
| 			{
 | |
| 				RaiseMessage("RaiseDataMessage:" + ex.Message, true);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 지정한 데이터로 바코드가 수신된것처럼 발생시킵니다.
 | |
| 		/// </summary>
 | |
| 		/// <param name="data"></param>
 | |
| 		public void RaiseRecvData(string data)
 | |
| 		{
 | |
| 			RaiseRecvData(System.Text.Encoding.Default.GetBytes(data));
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 메세지이벤트를 발생합니다. 오류메세지일 경우 2번째 파라미터를 true 로 입력하세요.
 | |
| 		/// </summary>
 | |
| 		/// <param name="message">메세지</param>
 | |
| 		/// <param name="isError">오류라면 True로 설정하세요. 기본값=False</param>
 | |
| 		public void RaiseMessage(string message, Boolean isError = false)
 | |
| 		{
 | |
| 			if (isError) errorMessage = message; //170920
 | |
| 			if (Message != null) Message(this, new MessageEventArgs(isError, message));
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 포트열기(실패시 False)를 반환
 | |
| 		/// </summary>
 | |
| 		public virtual Boolean Open(Boolean runInit = true)
 | |
| 		{
 | |
| 			try
 | |
| 			{
 | |
| 				_device.Open();
 | |
| 				if (_device.IsOpen)
 | |
| 				{
 | |
| 					Init();
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					_isinit = false;
 | |
| 				}
 | |
| 
 | |
| 				return _isinit;
 | |
| 			}
 | |
| 			catch (Exception ex)
 | |
| 			{
 | |
| 				errorMessage = ex.Message;
 | |
| 				RaiseMessage(ex.Message, true);
 | |
| 				return false;
 | |
| 			}
 | |
| 		}
 | |
| 		public virtual Boolean Open(string portname, int baud, Boolean runInit = true)
 | |
| 		{
 | |
| 			try
 | |
| 			{
 | |
| 				this.PortName = portname;
 | |
| 				this.BaudRate = baud;
 | |
| 				_device.Open();
 | |
| 				if (_device.IsOpen)
 | |
| 				{
 | |
| 					Init();
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					_isinit = false;
 | |
| 				}
 | |
| 
 | |
| 				return _isinit;
 | |
| 			}
 | |
| 			catch (Exception ex)
 | |
| 			{
 | |
| 				errorMessage = ex.Message;
 | |
| 				RaiseMessage(ex.Message, true);
 | |
| 				return false;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 포트닫기
 | |
| 		/// </summary>
 | |
| 		public virtual void Close()
 | |
| 		{
 | |
| 			if (_device != null && _device.IsOpen)
 | |
| 			{
 | |
| 				_isinit = false;
 | |
| 				_device.DiscardInBuffer();
 | |
| 				_device.DiscardOutBuffer();
 | |
| 
 | |
| 				//외부에서 닫기를 하면 진행된다?
 | |
| 				System.Threading.Tasks.Task.Run(new Action(() =>
 | |
| 				{
 | |
| 					_device.Close();
 | |
| 				}));
 | |
| 
 | |
| 
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 메세지내용중 Cr,LF 를 제거합니다.
 | |
| 		/// </summary>
 | |
| 		protected byte[] RemoveCRLF(byte[] src)
 | |
| 		{
 | |
| 			List<byte> bcdbuf = new List<byte>();
 | |
| 			foreach (byte by in src)
 | |
| 			{
 | |
| 				if (by == 0x00 || by == 0x0d || by == 0x0a || by == 0x02 || by == 0x03) continue;
 | |
| 				bcdbuf.Add(by);
 | |
| 			}
 | |
| 			return bcdbuf.ToArray();
 | |
| 		}
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region "Method Write Data"
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 포트에 쓰기(barcode_DataReceived 이벤트로 메세지수신)
 | |
| 		/// </summary>
 | |
| 		public virtual Boolean WriteData(string data)
 | |
| 		{
 | |
| 			byte[] buf = System.Text.Encoding.Default.GetBytes(data);
 | |
| 			return WriteData(buf);
 | |
| 		}
 | |
| 
 | |
| 		public virtual Boolean Write(string data)
 | |
| 		{
 | |
| 			return WriteData(data);
 | |
| 		}
 | |
| 		public virtual Boolean Write(byte[] buf)
 | |
| 		{
 | |
| 			return WriteData(buf);
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 포트에 쓰기 반환될 때까지 기다림(SyncTimeOut 값까지 기다림)
 | |
| 		/// </summary>
 | |
| 		public virtual byte[] WriteDataSync(string data)
 | |
| 		{
 | |
| 			byte[] buf = System.Text.Encoding.Default.GetBytes(data);
 | |
| 			return WriteDataSync(buf);
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// _buffer를 클리어하고 입력된 데이터를 버퍼에 추가합니다.
 | |
| 		/// </summary>
 | |
| 		/// <param name="buf"></param>
 | |
| 		public void setRecvBuffer(byte[] buf)
 | |
| 		{
 | |
| 			this._buffer.Clear();
 | |
| 			this._buffer.AddRange(buf);
 | |
| 		}
 | |
| 
 | |
| 		public int WriteError = 0;
 | |
| 		public string WriteErrorMessage = string.Empty;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 포트에 쓰기 반환될 때까지 기다림(SyncTimeOut 값까지 기다림)
 | |
| 		/// </summary>
 | |
| 		public virtual byte[] WriteDataSync(byte[] data, Boolean useReset = true)
 | |
| 		{
 | |
| 			errorMessage = string.Empty;
 | |
| 			_isSync = true;
 | |
| 			byte[] recvbuf = null;
 | |
| 			// Boolean bRet = false;
 | |
| 
 | |
| 			//171214
 | |
| 			if (!IsOpen())
 | |
| 			{
 | |
| 				errorMessage = "Port Closed";
 | |
| 				return null;
 | |
| 			}
 | |
| 
 | |
| 			//171205 : 타임아웃시간추가
 | |
| 			if (useReset)
 | |
| 			{
 | |
| 				if (!_mre.WaitOne(syncTimeout))
 | |
| 				{
 | |
| 					errorMessage = string.Format("WriteDataSync:MRE:WaitOne:TimeOut 3000ms");
 | |
| 					RaiseMessage(errorMessage, true);
 | |
| 					return null;
 | |
| 				}
 | |
| 
 | |
| 				_mre.Reset();
 | |
| 			}
 | |
| 
 | |
| 
 | |
| 			//save last command
 | |
| 			lastSendTime = DateTime.Now;
 | |
| 			if (lastSendBuffer == null) lastSendBuffer = new byte[data.Length]; //171113
 | |
| 			else Array.Resize(ref lastSendBuffer, data.Length);
 | |
| 			Array.Copy(data, lastSendBuffer, data.Length);
 | |
| 			Boolean sendOK = false;
 | |
| 
 | |
| 			try
 | |
| 			{
 | |
| 				_device.DiscardInBuffer();
 | |
| 				_device.DiscardOutBuffer();
 | |
| 				_buffer.Clear();    //171205
 | |
| 				_device.Write(data, 0, data.Length);
 | |
| 				WriteError = 0;
 | |
| 				WriteErrorMessage = string.Empty;
 | |
| 				sendOK = true;
 | |
| 			}
 | |
| 			catch (Exception ex)
 | |
| 			{
 | |
| 				WriteError += 1;
 | |
| 				WriteErrorMessage = ex.Message;
 | |
| 			}
 | |
| 
 | |
| 			if (sendOK)
 | |
| 			{
 | |
| 				try
 | |
| 				{
 | |
| 					//171113
 | |
| 					if (EnableTxMessage && SendData != null) SendData(this, new ReceiveDataEventArgs(data));
 | |
| 
 | |
| 					_wat.Restart();
 | |
| 					Boolean bTimeOut = false;
 | |
| 					_buffer.Clear();
 | |
| 					Boolean bDone = false;
 | |
| 					while (!bDone)
 | |
| 					{
 | |
| 						if (_wat.ElapsedMilliseconds > WriteTimeout)
 | |
| 						{
 | |
| 							errorMessage = "(Sync)WriteTimeOut";
 | |
| 							bTimeOut = true;
 | |
| 							break;
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							int RecvCnt = _device.BytesToRead;
 | |
| 							if (RecvCnt > 0)
 | |
| 							{
 | |
| 								byte[] rbuf = new byte[RecvCnt];
 | |
| 								_device.Read(rbuf, 0, rbuf.Length);
 | |
| 
 | |
| 								if (_term == eTerminal.CustomParser)
 | |
| 								{
 | |
| 									byte[] remainBuffer;
 | |
| 								Repeat:
 | |
| 									if (CustomParser(rbuf, out remainBuffer))
 | |
| 									{
 | |
| 										var newMem = new byte[_buffer.Count];
 | |
| 										_buffer.CopyTo(newMem);
 | |
| 										RaiseRecvData(newMem);
 | |
| 										bDone = true;
 | |
| 										if (remainBuffer != null && remainBuffer.Length > 0)
 | |
| 										{
 | |
| 											rbuf = new byte[remainBuffer.Length];
 | |
| 											Buffer.BlockCopy(remainBuffer, 0, rbuf, 0, rbuf.Length);
 | |
| 											goto Repeat;
 | |
| 										}
 | |
| 									}
 | |
| 								}
 | |
| 								else
 | |
| 								{
 | |
| 									foreach (byte b in rbuf)
 | |
| 									{
 | |
| 										if (CheckACK && b == 0x06)  //ack
 | |
| 										{
 | |
| 											_buffer.Add(b);
 | |
| 											bDone = true;
 | |
| 											break;
 | |
| 										}
 | |
| 										else if (CheckNAK && b == 0x15) //nak
 | |
| 										{
 | |
| 											_buffer.Add(b);
 | |
| 											bDone = true;
 | |
| 											break;
 | |
| 										}
 | |
| 										else
 | |
| 										{
 | |
| 											switch (_term)
 | |
| 											{
 | |
| 												case eTerminal.CR:
 | |
| 													if (b == 0x0D)
 | |
| 													{
 | |
| 														bDone = true;
 | |
| 														break;
 | |
| 													}
 | |
| 													else _buffer.Add(b);
 | |
| 													break;
 | |
| 												case eTerminal.LF:
 | |
| 													if (b == 0x0A)
 | |
| 													{
 | |
| 														bDone = true;
 | |
| 														break;
 | |
| 													}
 | |
| 													else _buffer.Add(b);
 | |
| 													break;
 | |
| 												case eTerminal.CRLF:
 | |
| 													if (b == 0x0A)
 | |
| 													{
 | |
| 														bDone = true;
 | |
| 														break;
 | |
| 													}
 | |
| 													else if (b == 0x0d)
 | |
| 													{
 | |
| 														//pass
 | |
| 													}
 | |
| 													else
 | |
| 													{
 | |
| 														_buffer.Add(b);
 | |
| 													}
 | |
| 													break;
 | |
| 												case eTerminal.Length:
 | |
| 													_buffer.Add(b);
 | |
| 													if (_buffer.Count == MaxDataLength)
 | |
| 													{
 | |
| 														bDone = true;
 | |
| 														break;
 | |
| 													}
 | |
| 													else if (_buffer.Count > MaxDataLength)
 | |
| 													{
 | |
| 														RaiseMessage("Buffer Length Error " + _buffer.Count.ToString() + "/" + MaxDataLength.ToString(), true);
 | |
| 														_buffer.Clear();
 | |
| 													}
 | |
| 
 | |
| 													break;
 | |
| 												case eTerminal.ETX:
 | |
| 
 | |
| 													if (b == STX)
 | |
| 													{
 | |
| 														_buffer.Clear();
 | |
| 													}
 | |
| 													else if (b == ETX)
 | |
| 													{
 | |
| 														bDone = true;
 | |
| 														break;
 | |
| 													}
 | |
| 													else _buffer.Add(b);
 | |
| 													break;
 | |
| 											}
 | |
| 										}
 | |
| 
 | |
| 									}
 | |
| 								}
 | |
| 							}
 | |
| 
 | |
| 						}
 | |
| 					}
 | |
| 					_wat.Stop();
 | |
| 					if (!bTimeOut)
 | |
| 					{
 | |
| 						recvbuf = new byte[_buffer.Count];
 | |
| 						Buffer.BlockCopy(_buffer.ToArray(), 0, recvbuf, 0, recvbuf.Length);
 | |
| 						//recvbuf = _buffer.ToArray();
 | |
| 						// bRet = true;
 | |
| 					}
 | |
| 				}
 | |
| 				catch (Exception ex)
 | |
| 				{
 | |
| 					errorMessage = ex.Message;
 | |
| 					//bRet = false;
 | |
| 				}
 | |
| 				finally
 | |
| 				{
 | |
| 					if (useReset)
 | |
| 						_mre.Set();//release
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			//syncmode off
 | |
| 			_isSync = false;
 | |
| 			return recvbuf;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 포트에 쓰기(barcode_DataReceived 이벤트로 메세지수신)
 | |
| 		/// </summary>
 | |
| 		public virtual Boolean WriteData(byte[] data)
 | |
| 		{
 | |
| 			Boolean bRet = false;
 | |
| 
 | |
| 			//171205 : 타임아웃시간추가
 | |
| 			if (!_mre.WaitOne(3000))
 | |
| 			{
 | |
| 				errorMessage = string.Format("WriteData:MRE:WaitOne:TimeOut 3000ms");
 | |
| 				RaiseMessage(errorMessage, true);
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			_mre.Reset();
 | |
| 
 | |
| 			//Array.Resize(ref data, data.Length + 2);
 | |
| 
 | |
| 			try
 | |
| 			{
 | |
| 				lastSendTime = DateTime.Now;
 | |
| 				if (lastSendBuffer == null) lastSendBuffer = new byte[data.Length]; //171113
 | |
| 				else Array.Resize(ref lastSendBuffer, data.Length);
 | |
| 				Array.Copy(data, lastSendBuffer, data.Length);
 | |
| 				_device.Write(data, 0, data.Length);
 | |
| 
 | |
| 				//171113
 | |
| 				if (EnableTxMessage && SendData != null) SendData(this, new ReceiveDataEventArgs(data));
 | |
| 
 | |
| 				bRet = true;
 | |
| 				WriteError = 0;
 | |
| 				WriteErrorMessage = string.Empty;
 | |
| 			}
 | |
| 			catch (Exception ex)
 | |
| 			{
 | |
| 				// this.isinit = false;
 | |
| 				RaiseMessage(ex.Message, true);// if (ReceivceData != null) ReceivceData(this, true, ex.Message);
 | |
| 				bRet = false;
 | |
| 				WriteError += 1; //연속쓰기오류횟수
 | |
| 				WriteErrorMessage = ex.Message;
 | |
| 			}
 | |
| 			finally
 | |
| 			{
 | |
| 				_mre.Set();
 | |
| 			}
 | |
| 			return bRet;
 | |
| 		}
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// 지정한ID를 가진 장치를 생성합니다.
 | |
| 		/// </summary>
 | |
| 		/// <param name="id"></param>
 | |
| 		public RS232(string tag_ = "")
 | |
| 		{
 | |
| 			_mre = new ManualResetEvent(true);
 | |
| 			this.Tag = tag_;
 | |
| 			this._device = new System.IO.Ports.SerialPort();
 | |
| 
 | |
| 			_device.DataReceived += barcode_DataReceived;
 | |
| 			_device.ErrorReceived += barcode_ErrorReceived;
 | |
| 			_device.PinChanged += barcode_PinChanged;
 | |
| 			_device.ReadTimeout = 2000;
 | |
| 			_device.WriteTimeout = 2000;
 | |
| 			_device.BaudRate = 9600;
 | |
| 			_term = eTerminal.CRLF;
 | |
| 			STX = 0x02;
 | |
| 			ETX = 0x03;
 | |
| 			RemoveCRLFNULL = false;
 | |
| 			EnableTxMessage = false;
 | |
| 		}
 | |
| 
 | |
| 		~RS232()
 | |
| 		{
 | |
| 			Dispose();
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// close를 호출합니다.
 | |
| 		/// </summary>
 | |
| 		public virtual void Dispose()
 | |
| 		{
 | |
| 			if (!isDisposed) //180219
 | |
| 			{
 | |
| 				isDisposed = true;
 | |
| 				_isinit = false;
 | |
| 				_device.DataReceived -= barcode_DataReceived;
 | |
| 				_device.ErrorReceived -= barcode_ErrorReceived;
 | |
| 				_device.PinChanged -= barcode_PinChanged;
 | |
| 				Close();
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | 
