1097 lines
36 KiB
C#
1097 lines
36 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.ComponentModel;
|
|
using System.Threading;
|
|
|
|
namespace Project.Device
|
|
{
|
|
public class Barcode : IDisposable
|
|
{
|
|
protected Boolean _isinit = false;
|
|
|
|
#region "Event Args"
|
|
|
|
/// <summary>
|
|
/// 데이터를 수신할떄 사용함(RAW 포함)
|
|
/// </summary>
|
|
public class ReceiveDataEventArgs : EventArgs
|
|
{
|
|
private 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 Boolean _isError = false;
|
|
public Boolean IsError { get { return _isError; } }
|
|
private 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>
|
|
/// 오류가 발생했다면 이 변수에 그 내용이 기록됩니다.
|
|
/// </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"
|
|
|
|
/// <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_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
|
|
{
|
|
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 int ID { 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
|
|
{
|
|
get
|
|
{
|
|
if (_device == null) return false;
|
|
return _device.IsOpen;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 초기화등이 성공했는지 확인합니다.close 되었다면 실패입니다. isinit 변수값을 적절히 수정하시기 바랍니다.
|
|
/// </summary>
|
|
[Description("초기화성공여부 별도의 초기화 코드가없다면 isOpen 과 동일합니다.")]
|
|
[Category("정보"), DisplayName("Init OK?")]
|
|
public virtual Boolean IsInit
|
|
{
|
|
get
|
|
{
|
|
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 { _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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 포트닫기
|
|
/// </summary>
|
|
public virtual void Close(Boolean PortClose = true)
|
|
{
|
|
if (_device != null && _device.IsOpen)
|
|
{
|
|
_isinit = false;
|
|
_device.DiscardInBuffer();
|
|
_device.DiscardOutBuffer();
|
|
if (PortClose) _device.Close(); //dispose에서는 포트를 직접 클리어하지 않게 해뒀다.
|
|
}
|
|
}
|
|
|
|
/// <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);
|
|
}
|
|
|
|
/// <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(3000))
|
|
{
|
|
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))
|
|
{
|
|
RaiseRecvData(_buffer.ToArray());
|
|
bDone = true;
|
|
if (remainBuffer != null && remainBuffer.Length > 0)
|
|
{
|
|
rbuf = new byte[remainBuffer.Length];
|
|
Array.Copy(remainBuffer, rbuf, rbuf.Length);
|
|
goto Repeat;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach (byte b in rbuf)
|
|
{
|
|
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 = _buffer.ToArray();
|
|
bRet = true;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
errorMessage = ex.Message;
|
|
bRet = false;
|
|
}
|
|
}
|
|
|
|
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>
|
|
/// 장치를 생성합니다.
|
|
/// </summary>
|
|
public Barcode() : this(0) { }
|
|
/// <summary>
|
|
/// 지정한ID를 가진 장치를 생성합니다.
|
|
/// </summary>
|
|
/// <param name="id"></param>
|
|
public Barcode(int id)
|
|
{
|
|
_mre = new ManualResetEvent(true);
|
|
this.ID = id;
|
|
this._device = new System.IO.Ports.SerialPort();
|
|
_device.DataReceived += barcode_DataReceived;
|
|
_device.ErrorReceived += barcode_ErrorReceived;
|
|
_device.ReadTimeout = 2000;
|
|
_device.WriteTimeout = 2000;
|
|
_term = eTerminal.CrLf;
|
|
STX = 0x02;
|
|
ETX = 0x03;
|
|
RemoveCRLFNULL = false;
|
|
EnableTxMessage = false;
|
|
}
|
|
|
|
~Barcode()
|
|
{
|
|
Dispose();
|
|
}
|
|
|
|
/// <summary>
|
|
/// close를 호출합니다.
|
|
/// </summary>
|
|
public virtual void Dispose()
|
|
{
|
|
if (!isDisposed) //180219
|
|
{
|
|
_isinit = false;
|
|
_device.DataReceived -= barcode_DataReceived;
|
|
_device.ErrorReceived -= barcode_ErrorReceived;
|
|
//Close(false);
|
|
isDisposed = true;
|
|
}
|
|
}
|
|
}
|
|
}
|