From d777adc21976d5210977b7297dfd508d4da0a280 Mon Sep 17 00:00:00 2001 From: ChiKyun Kim Date: Thu, 18 Dec 2025 14:44:00 +0900 Subject: [PATCH] =?UTF-8?q?BMS=20=EB=A5=BC=20RS232=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=EC=97=90=EC=84=9C=20=ED=8F=B4=EB=A7=81=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=20=EC=A0=84=EC=9A=A9=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20BMS=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EC=A4=91=20=ED=98=84=EC=9E=AC=20=EC=82=AC=EC=9A=A9=20=EC=A0=84?= =?UTF-8?q?=EB=A5=98=EC=99=80=20=EC=99=80=ED=8A=B8=EB=A5=BC=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C=ED=95=A8=20=EC=82=AC=EC=9A=A9=EC=A0=84=EB=A5=98?= =?UTF-8?q?=EB=A5=BC=20=ED=86=B5=ED=95=B4=EC=84=9C=20=EC=B6=A9=EC=A0=84?= =?UTF-8?q?=EC=97=AC=EB=B6=80=EB=A5=BC=20=EC=9E=90=EB=8F=99=20=ED=8C=90?= =?UTF-8?q?=EB=8B=A4=EC=8B=9C=ED=82=A4=EA=B3=A0,=20=ED=95=B4=EB=8B=B9=20?= =?UTF-8?q?=EA=B0=92=EC=9D=80=20Manual=20Charge=20=ED=94=8C=EB=9E=98?= =?UTF-8?q?=EA=B7=B8=EC=97=90=20=EC=84=A4=EC=A0=95=ED=95=A8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cs_HMI/Project/AGV4.csproj | 1 + Cs_HMI/Project/Device/BMS.cs | 187 +++--- .../Project/Device/BMSInformationEventArgs.cs | 16 +- Cs_HMI/Project/Device/BMSSerialComm.cs | 607 ++++++++++++++++++ Cs_HMI/Project/Dialog/fLog.Designer.cs | 140 ++-- Cs_HMI/Project/StateMachine/_AGV.cs | 3 +- Cs_HMI/Project/StateMachine/_BMS.cs | 42 +- Cs_HMI/Project/StateMachine/_SPS.cs | 11 +- Cs_HMI/Project/fMain.cs | 14 +- Cs_HMI/StateMachine/StateMachine.cs | 14 +- Cs_HMI/SubProject/AGV/NarumiSerialComm.cs | 2 +- 11 files changed, 824 insertions(+), 213 deletions(-) create mode 100644 Cs_HMI/Project/Device/BMSSerialComm.cs diff --git a/Cs_HMI/Project/AGV4.csproj b/Cs_HMI/Project/AGV4.csproj index 119d01b..1ee4984 100644 --- a/Cs_HMI/Project/AGV4.csproj +++ b/Cs_HMI/Project/AGV4.csproj @@ -186,6 +186,7 @@ + Component diff --git a/Cs_HMI/Project/Device/BMS.cs b/Cs_HMI/Project/Device/BMS.cs index a19a089..34e9776 100644 --- a/Cs_HMI/Project/Device/BMS.cs +++ b/Cs_HMI/Project/Device/BMS.cs @@ -9,12 +9,12 @@ using System.CodeDom; namespace arDev { - public class BMS : arRS232 + public class BMS : BMSSerialComm { public BMS() { - MinRecvLength = 34; + } /// @@ -55,28 +55,60 @@ namespace arDev { tempBuffer.Add(incomByte); - var queylen = QueryIndex == 0 ? 34 : 23; - if (tempBuffer.Count == queylen) + if (tempBuffer.Count > 7) { - if (incomByte != 0x77) + byte len = tempBuffer[3]; + if (tempBuffer.Count >= 4 + len + 3) // Start+Reg+Status+Len + Data + Chk(2) + End { - //종단기호가 맞지 않다. 이자료는 폐기한다. - var hexstr = string.Join(" ", tempBuffer.Select(t => t.ToString("X2"))); - RaiseMessage(MessageType.Error, $"discard : {hexstr}"); - tempBuffer.Clear(); + if (tempBuffer.Last() == 0x77) + { + //데이터가 맞게 수신됨 + LastReceiveBuffer = tempBuffer.ToArray(); + bComplete = true; + } + else + { + //종단기호가 맞지 않다. 이자료는 폐기한다. + var hexstr = string.Join(" ", tempBuffer.Select(t => t.ToString("X2"))); + RaiseMessage(MessageType.Error, $"discard : {hexstr}"); + tempBuffer.Clear(); + } + findSTX = false; } - else - { - //데이터가 맞게 수신됨 - LastReceiveBuffer = tempBuffer.ToArray(); - bComplete = true; - } - findSTX = false; - } - else - { - //아직 모자르므로 대기한다 } + +// [22 - 12 - 27 14:32:49] open: True +//[22 - 12 - 27 14:32:49] Send: DD A5 03 00 FF FD 77 0D +//[22 - 12 - 27 14:32:50] Send: DD A5 03 00 FF FD 77 0D +//[22 - 12 - 27 14:32:50] Recv: 26.61v,81.4 % +//[22 - 12 - 27 14:32:50] Recv: DD 03 00 1B 0A 65 00 00 21 63 29 04 00 00 2C 92 00 00 00 00 00 00 28 51 03 08 02 0B 69 0B 66 FC 9C 77 +//[22 - 12 - 27 14:32:50] Send: DD A5 03 00 FF FD 77 0D +//[22 - 12 - 27 14:32:51] Recv: 26.61v,81.4 % +//[22 - 12 - 27 14:32:51] Recv: DD 03 00 1B 0A 65 00 00 21 63 29 04 00 00 2C 92 00 00 00 00 00 00 28 51 03 08 02 0B 69 0B 66 FC 9C 77 + + + //var queylen = QueryIndex == 0 ? 34 : 23; + //if (tempBuffer.Count == queylen) + //{ + // if (incomByte != 0x77) + // { + // //종단기호가 맞지 않다. 이자료는 폐기한다. + // var hexstr = string.Join(" ", tempBuffer.Select(t => t.ToString("X2"))); + // RaiseMessage(MessageType.Error, $"discard : {hexstr}"); + // tempBuffer.Clear(); + // } + // else + // { + // //데이터가 맞게 수신됨 + // LastReceiveBuffer = tempBuffer.ToArray(); + // bComplete = true; + // } + // findSTX = false; + //} + //else + //{ + // //아직 모자르므로 대기한다 + //} } } } @@ -106,7 +138,7 @@ namespace arDev else { var rxstr = string.Join(" ", data.Select(t => t.ToString("X2"))); - RaiseMessage(MessageType.Recv, $"Querh:{QueryIndex},Data:{rxstr}"); + RaiseMessage(MessageType.Recv, rxstr); } if (QueryIndex == 0) @@ -231,98 +263,65 @@ namespace arDev return false; } } - - private bool _autocharge = false; - public Boolean AutoCharge - { - get { return _autocharge; } - set { _autocharge = false; } - } - - //public void ClearManualChargeCheckValue() - //{ - // chk_timee = new DateTime(1982, 11, 23); - // chk_times = new DateTime(1982, 11, 23); - // chk_valuee = 0f; - // chk_values = 0f; - //} - + /// + /// 현재 충전중인지? + /// + public bool IsCharging { get; private set; } + DateTime ChargeStart = DateTime.Now; + DateTime ChargeEnd = DateTime.Now; void CheckManualCharge() { - if (AutoCharge) + //충방전전력이 1보다 크면 충전으로 한다. + if (Charge_Amp > 0.1) { - if (chk_timee.Year != 1982) + //기존에 충전상태가 OFF였다면 충전중으로 알려준다 + if (IsCharging == false) { - chk_timee = new DateTime(1982, 11, 23); - chk_valuee = 999f; + IsCharging = true; + ChargeStart = DateTime.Now; + ChargeEnd = new DateTime(1982, 11, 23); + try + { + ChargeDetect?.Invoke(this, new ChargetDetectArgs(ChargeStart, true, Current_Level)); + } + catch (Exception ex) { RaiseMessage(MessageType.Error, ex.Message); } } - if (chk_times.Year != 1982) + else { - chk_times = new DateTime(1982, 11, 23); - chk_values = 999f; + //충전상태가 유지되고 있다. } } - if (chk_times.Year == 1982) - { - chk_times = DateTime.Now; - chk_values = Current_Level; - } else { - if (chk_timee.Year == 1982) + //충전이해제되었다.. 단 바로 해제하지않고 1초정도 텀을 주고 OFF한다. + if (IsCharging) { - if ((Current_Level - chk_values) >= 0.1) + if (ChargeEnd.Year == 1982) { - //충전중이다 - chk_timee = DateTime.Now; - chk_valuee = Current_Level; - try - { - ChargeDetect?.Invoke(this, new ChargetDetectArgs(chk_times, chk_values, chk_timee, chk_valuee)); - } - catch (Exception ex) { RaiseMessage(MessageType.Error, ex.Message); } - - } - else if ((Current_Level - chk_values) <= -0.1) - { - //방전중이다 - if (chk_times.Year != 1982) chk_times = new DateTime(1982, 11, 23); - if (chk_timee.Year != 1982) chk_timee = new DateTime(1982, 11, 23); + ChargeEnd = DateTime.Now; } else { - //아직 변화가 없으니 종료일을 기록하지 않는다 + var ts = DateTime.Now - ChargeEnd; + if (ts.TotalSeconds > 2) //충전종료시그널후 2초후에 충전off를 알린다. + { + ChargeEnd = DateTime.Now; + IsCharging = false; + try + { + ChargeDetect?.Invoke(this, new ChargetDetectArgs(ChargeEnd, false, Current_Level)); + } + catch (Exception ex) { RaiseMessage(MessageType.Error, ex.Message); } + } } } else { - //이미 종료일이 셋팅된 상태이다 - if ((Current_Level - chk_valuee) >= 0.1) - { - //종료시간을 시작값에 넣는다 - chk_times = chk_timee; - chk_values = chk_valuee; - - chk_timee = DateTime.Now; - chk_valuee = Current_Level; - try - { - ChargeDetect?.Invoke(this, new ChargetDetectArgs(chk_times, chk_values, chk_timee, chk_valuee)); - } - catch (Exception ex) { RaiseMessage(MessageType.Error, ex.Message); } - } - else if ((Current_Level - chk_valuee) <= -0.1) - { - //방전중이다 - if (chk_times.Year != 1982) chk_times = new DateTime(1982, 11, 23); - if (chk_timee.Year != 1982) chk_timee = new DateTime(1982, 11, 23); - } - else - { - //아직 변화가 없으니 종료일을 기록하지 않는다 - } + //방전상태가 유지되고 있다. } } + + } public DateTime chk_times { get; set; } = new DateTime(1982, 11, 23); @@ -335,7 +334,7 @@ namespace arDev { get { - return (Int16)((Charge_Amp ) * Current_Volt); + return (Int16)((Charge_Amp) * Current_Volt); } } /// @@ -421,6 +420,7 @@ namespace arDev cmd.Add(0xFD); cmd.Add(0x77); //cmd.Add(0x0D); + //_device.DiscardInBuffer(); return WriteData(cmd.ToArray()); } @@ -437,6 +437,7 @@ namespace arDev cmd.Add(0xFC); cmd.Add(0x77); //cmd.Add(0x0D); + //_device.DiscardInBuffer(); return WriteData(cmd.ToArray()); } diff --git a/Cs_HMI/Project/Device/BMSInformationEventArgs.cs b/Cs_HMI/Project/Device/BMSInformationEventArgs.cs index d4a3636..5627723 100644 --- a/Cs_HMI/Project/Device/BMSInformationEventArgs.cs +++ b/Cs_HMI/Project/Device/BMSInformationEventArgs.cs @@ -4,16 +4,14 @@ namespace arDev { public class ChargetDetectArgs : EventArgs { - public DateTime times { get; set; } - public DateTime timee { get; set; } - public float values { get; set; } - public float valuee { get; set; } - public ChargetDetectArgs(DateTime times, float values, DateTime timee, float valuee) + public DateTime time { get; set; } + public float level { get; set; } + public bool Detected { get; set; } + public ChargetDetectArgs(DateTime times, bool detected, float values) { - this.times = times; - this.times = timee; - this.values = values; - this.valuee = valuee; + this.time = times; + this.level = values; + this.Detected = detected; } } public class BMSInformationEventArgs : EventArgs diff --git a/Cs_HMI/Project/Device/BMSSerialComm.cs b/Cs_HMI/Project/Device/BMSSerialComm.cs new file mode 100644 index 0000000..3f9b42e --- /dev/null +++ b/Cs_HMI/Project/Device/BMSSerialComm.cs @@ -0,0 +1,607 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading; + +namespace arDev +{ + public abstract class BMSSerialComm : ISerialComm, IDisposable + { + protected System.IO.Ports.SerialPort _device; + protected ManualResetEvent _mre; + protected byte[] LastReceiveBuffer = new byte[] { }; + /// + /// 최종 전송 메세지 + /// + public byte[] lastSendBuffer = new byte[] { }; + //public int ValidCheckTimeMSec { get; set; } = 5000; + protected List tempBuffer = new List(); + protected Boolean findSTX = false; + public string ErrorMessage { get; set; } + public DateTime LastConnTime { get; set; } + public DateTime LastConnTryTime { get; set; } + public DateTime lastSendTime; + /// + /// 메세지 수신시 사용하는 내부버퍼 + /// + protected List _buffer = new List(); + /// + /// 데이터조회간격(초) + /// + public float ScanInterval { get; set; } + + // public byte[] LastRecvData; + public string LastRecvString + { + get + { + if (LastReceiveBuffer == null) return String.Empty; + else return System.Text.Encoding.Default.GetString(LastReceiveBuffer); + } + } + /// + /// 마지막으로 데이터를 받은 시간 + /// + public DateTime lastRecvTime; + + + public int WriteError = 0; + public string WriteErrorMessage = string.Empty; + public int WaitTimeout { get; set; } = 1000; + public int MinRecvLength { get; set; } = 1; + + // Polling Thread related + protected Thread _recvThread; + protected volatile bool _isReading = false; + + + /// + /// 포트이름 + /// + [Description("시리얼 포트 이름")] + [Category("설정"), DisplayName("Port Name")] + public string PortName + { + get + { + if (_device == null) return string.Empty; + else return _device.PortName; + } + set + { + if (this.IsOpen) + { + Message?.Invoke(this, new MessageEventArgs("포트가 열려있어 포트이름을 변경할 수 없습니다", true)); + } + else if (String.IsNullOrEmpty(value) == false) + _device.PortName = value; + else + { + Message?.Invoke(this, new MessageEventArgs("No PortName", true)); + } + } + } + + public int BaudRate + { + get + { + if (_device == null) return 0; + else return _device.BaudRate; + } + set + { + if (this.IsOpen) + { + Message?.Invoke(this, new MessageEventArgs("포트가 열려있어 BaudRate(를) 변경할 수 없습니다", true)); + } + else if (value != 0) + _device.BaudRate = value; + else Message?.Invoke(this, new MessageEventArgs("No baud rate", true)); + } + } + + + public BMSSerialComm() + { + _device = new System.IO.Ports.SerialPort(); + this.BaudRate = 9600; + ScanInterval = 10; + // _device.DataReceived += barcode_DataReceived; // Removed event handler + _device.ErrorReceived += this.barcode_ErrorReceived; + _device.WriteTimeout = 3000; + _device.ReadTimeout = 3000; + _device.ReadBufferSize = 8192; + _device.WriteBufferSize = 8192; + //_device.DiscardInBuffer(); + //_device.DiscardOutBuffer(); + ErrorMessage = string.Empty; + lastRecvTime = DateTime.Parse("1982-11-23"); + LastConnTime = DateTime.Parse("1982-11-23"); + LastConnTryTime = DateTime.Parse("1982-11-23"); + lastRecvTime = DateTime.Parse("1982-11-23"); + this._mre = new ManualResetEvent(true); + } + + ~BMSSerialComm() + { + Dispose(false); + } + + + // Flag: Has Dispose already been called? + bool disposed = false; + + // Public implementation of Dispose pattern callable by consumers. + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + // Protected implementation of Dispose pattern. + protected virtual void Dispose(bool disposing) + { + if (disposed) + return; + + if (disposing) + { + // Free any other managed objects here. + // + } + + // Stop reading thread + _isReading = false; + + // _device.DataReceived -= barcode_DataReceived; // Removed event handler + _device.ErrorReceived -= this.barcode_ErrorReceived; + + if (_recvThread != null && _recvThread.IsAlive) + { + _recvThread.Join(500); + } + + if (_device != null) + { + if (_device.IsOpen) _device.Close(); + _device.Dispose(); + } + + // Free any unmanaged objects here. + // + disposed = true; + } + + public Boolean Open() + { + try + { + if (_device.IsOpen == false) + { + _device.Open(); + } + + if (_device.IsOpen) + { + // Start polling thread + if (_isReading == false) + { + _isReading = true; + _recvThread = new Thread(ReadPort); + _recvThread.IsBackground = true; + _recvThread.Start(); + } + return true; + } + return false; + } + catch (Exception ex) + { + ErrorMessage = ex.Message; + Message.Invoke(this, new MessageEventArgs(ex.Message, true)); + return false; + } + } + public string GetHexString(Byte[] input) + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + foreach (byte b in input) + sb.Append(" " + b.ToString("X2")); + return sb.ToString(); + } + + /// + /// 포트가 열려있는지 확인 + /// + [Description("현재 시리얼포트가 열려있는지 확인합니다")] + [Category("정보"), DisplayName("Port Open")] + public Boolean IsOpen + { + get + { + if (_device == null) return false; + return _device.IsOpen; + } + } + + public virtual bool Close() + { + try + { + _isReading = false; // Stop thread loop + + if (_recvThread != null && _recvThread.IsAlive) + { + if (!_recvThread.Join(500)) // Wait for thread to finish + { + // _recvThread.Abort(); // Avoid Abort if possible + } + } + + if (_device != null && _device.IsOpen) + { + _device.DiscardInBuffer(); + _device.DiscardOutBuffer(); + _device.Close(); //dispose에서는 포트를 직접 클리어하지 않게 해뒀다. + return true; + } + else return false; + } + catch (Exception) + { + return false; + } + } + protected Boolean RaiseRecvData() + { + return RaiseRecvData(LastReceiveBuffer.ToArray(), false); + } + /// + /// 수신받은 메세지를 발생 시킵니다 + /// + /// + /// + public virtual Boolean RaiseRecvData(byte[] Data, bool udpatelastbuffer) + { + //181206 - 최종수신 메세지 기록 + lastRecvTime = DateTime.Now; + if (udpatelastbuffer && Data != null) + { + if (LastReceiveBuffer == null || LastReceiveBuffer.Length != Data.Length) + { + LastReceiveBuffer = new byte[Data.Length]; + Array.Copy(Data, LastReceiveBuffer, Data.Length); + } + } + + try + { + // UI update might need Invoke if this event handler updates UI directly, + // but usually the subscriber handles Invoke. + // Since we are running on a background thread now, subscribers must be aware. + Message?.Invoke(this, new MessageEventArgs(Data, true)); //recvmessage + if (ProcessRecvData(Data) == false) + { + //Message?.Invoke(this, new MessageEventArgs(Data, true)); //recvmessage + Message?.Invoke(this, new MessageEventArgs(this.ErrorMessage, true)); //errormessage + return false; + } + else + { + + return true; + } + } + catch (Exception ex) + { + this.ErrorMessage = ex.Message; + this.Message?.Invoke(this, new MessageEventArgs(ex.Message, true)); + return false; + } + } + + /// + /// 수신받은 자료를 처리한다 + /// + /// + /// + public abstract bool ProcessRecvData(byte[] data); + + #region "Internal Events" + + void barcode_ErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e) + { + Message?.Invoke(this, new MessageEventArgs(e.ToString(), true)); + } + + byte[] buffer = new byte[] { }; + + // Replaced with ReadPort Loop + /* + void barcode_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) + { + + try + { + int ReadCount = _device.BytesToRead; + + buffer = new byte[ReadCount]; + _device.Read(buffer, 0, buffer.Length); + + System.Text.StringBuilder LogMsg = new StringBuilder(); + + byte[] remainBuffer; + Repeat: + if (CustomParser(buffer, out remainBuffer)) + { + //분석완료이므로 받은 데이터를 버퍼에 기록한다 + if (LastReceiveBuffer == null || (LastReceiveBuffer.Length != tempBuffer.Count)) + Array.Resize(ref LastReceiveBuffer, tempBuffer.Count); + Array.Copy(tempBuffer.ToArray(), LastReceiveBuffer, tempBuffer.Count); + tempBuffer.Clear(); + + //수신메세지발생 + RaiseRecvData(); + if (remainBuffer != null && remainBuffer.Length > 0) + { + //버퍼를 변경해서 다시 전송을 해준다. + Array.Resize(ref buffer, remainBuffer.Length); + Array.Copy(remainBuffer, buffer, remainBuffer.Length); + goto Repeat; //남은 버퍼가 있다면 진행을 해준다. + } + } + + } + catch (Exception ex) + { + //if (IsOpen) + //{ + // //_device.DiscardInBuffer(); + // //_device.DiscardOutBuffer(); + //} + ErrorMessage = ex.Message; + this.Message?.Invoke(this, new MessageEventArgs(ex.Message, true)); + } + + } + */ + + void ReadPort() + { + while (_isReading) + { + try + { + if (_device == null || !_device.IsOpen) + { + Thread.Sleep(100); + continue; + } + + int readCount = _device.BytesToRead; + if (readCount > 0) + { + byte[] buffer = new byte[readCount]; + _device.Read(buffer, 0, buffer.Length); + + byte[] remainBuffer; + Repeat: + if (CustomParser(buffer, out remainBuffer)) + { + //분석완료이므로 받은 데이터를 버퍼에 기록한다 + if (LastReceiveBuffer == null || (LastReceiveBuffer.Length != tempBuffer.Count)) + Array.Resize(ref LastReceiveBuffer, tempBuffer.Count); + Array.Copy(tempBuffer.ToArray(), LastReceiveBuffer, tempBuffer.Count); + tempBuffer.Clear(); + + //수신메세지발생 + RaiseRecvData(); + if (remainBuffer != null && remainBuffer.Length > 0) + { + //버퍼를 변경해서 다시 전송을 해준다. + buffer = new byte[remainBuffer.Length]; // Reallocate buffer for remaining data + Array.Copy(remainBuffer, buffer, remainBuffer.Length); + goto Repeat; //남은 버퍼가 있다면 진행을 해준다. + } + } + } + else + { + Thread.Sleep(20); // Data 없음, 대기 + } + } + catch (Exception ex) + { + // Thread 상에서 Exception 발생 시 로그 남기고 계속 진행 여부 결정 + // 여기서는 에러 메시지 발생시키고 Sleep + ErrorMessage = ex.Message; + this.Message?.Invoke(this, new MessageEventArgs(ex.Message, true)); + Thread.Sleep(1000); + } + } + } + + + #endregion + + #region "External Events" + + + /// + /// 오류 및 기타 일반 메세지 + /// + public event EventHandler Message; + + #endregion + + #region "Event Args" + + /// + /// 데이터를 수신할떄 사용함(RAW 포함) + /// + public class ReceiveDataEventArgs : EventArgs + { + private byte[] _buffer = null; + + /// + /// 바이트배열의 버퍼값 + /// + public byte[] Value { get { return _buffer; } } + + /// + /// 버퍼(바이트배열)의 데이터를 문자로 반환합니다. + /// + 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; + } + } + + /// + /// 메세지를 강제 발생 + /// + /// + /// + protected virtual void RaiseMessage(MessageType mt, string message) + { + this.Message?.Invoke(this, new MessageEventArgs(mt, message)); + } + public enum MessageType + { + Normal, + Error, + Send, + Recv, + } + + public class MessageEventArgs : EventArgs + { + public MessageType MsgType { get; set; } + private string _message = string.Empty; + + /// + /// Recv,Send,Normal,Error 모두 지원 + /// + public string Message { get { return _message; } } + + private byte[] _data = null; + + /// + /// Recv,Send에서만 값이 존재 합니다 + /// + public byte[] Data { get { return _data; } } + public MessageEventArgs(string Message, bool isError = false) + { + if (isError) MsgType = MessageType.Error; + else MsgType = MessageType.Normal; + _message = Message; + } + public MessageEventArgs(MessageType msgtype, string Message) + { + MsgType = msgtype; + _message = Message; + _data = System.Text.Encoding.Default.GetBytes(Message); + } + + public MessageEventArgs(byte[] buffer, bool isRecv = true) + { + if (isRecv) MsgType = MessageType.Recv; + else MsgType = MessageType.Send; + _data = new byte[buffer.Length]; + Array.Copy(buffer, _data, Data.Length); + _message = System.Text.Encoding.Default.GetString(_data); + } + + } + + #endregion + + protected abstract bool CustomParser(byte[] buf, out byte[] remainBuffer); + + /// + /// 포트가 열려있거나 데이터 수신시간이 없는경우 false를 반환합니다 + /// + public Boolean IsValid + { + get + { + if (IsOpen == false) return false; + if (lastRecvTime.Year == 1982) return false; + var ts = DateTime.Now - lastRecvTime; + if (ts.TotalSeconds > (this.ScanInterval * 2.5)) return false; + return true; + } + } + protected bool WriteData(string cmd) + { + return WriteData(System.Text.Encoding.Default.GetBytes(cmd)); + } + /// + /// 포트에 쓰기(barcode_DataReceived 이벤트로 메세지수신) + /// + protected Boolean WriteData(byte[] data) + { + Boolean bRet = false; + + //171205 : 타임아웃시간추가 + if (!_mre.WaitOne(WaitTimeout)) + { + ErrorMessage = $"WriteData:MRE:WaitOne:TimeOut {WaitTimeout}ms"; + this.Message?.Invoke(this, new MessageEventArgs(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); + + for (int i = 0; i < data.Length; i++) + _device.Write(data, i, 1); + + //_device.Write(data, 0, data.Length); + + //171113 + this.Message?.Invoke(this, new MessageEventArgs(data, false)); + + bRet = true; + WriteError = 0; + WriteErrorMessage = string.Empty; + } + catch (Exception ex) + { + // this.isinit = false; + this.Message?.Invoke(this, new MessageEventArgs(ex.Message, true)); + bRet = false; + WriteError += 1; //연속쓰기오류횟수 + WriteErrorMessage = ex.Message; + } + finally + { + _mre.Set(); + } + return bRet; + } + } + + +} diff --git a/Cs_HMI/Project/Dialog/fLog.Designer.cs b/Cs_HMI/Project/Dialog/fLog.Designer.cs index 3f88031..b671af0 100644 --- a/Cs_HMI/Project/Dialog/fLog.Designer.cs +++ b/Cs_HMI/Project/Dialog/fLog.Designer.cs @@ -31,16 +31,15 @@ this.rtsys = new arCtl.LogTextBox(); this.rtTx = new arCtl.LogTextBox(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); - this.rtAGV = new arCtl.LogTextBox(); - this.rtBMS = new arCtl.LogTextBox(); - this.rtXbee = new arCtl.LogTextBox(); this.panel1 = new System.Windows.Forms.Panel(); + this.rtXbee = new arCtl.LogTextBox(); this.label1 = new System.Windows.Forms.Label(); this.panel2 = new System.Windows.Forms.Panel(); - this.panel3 = new System.Windows.Forms.Panel(); - this.panel4 = new System.Windows.Forms.Panel(); - this.label2 = new System.Windows.Forms.Label(); + this.rtBMS = new arCtl.LogTextBox(); this.label3 = new System.Windows.Forms.Label(); + this.panel4 = new System.Windows.Forms.Panel(); + this.rtAGV = new arCtl.LogTextBox(); + this.label2 = new System.Windows.Forms.Label(); this.tableLayoutPanel1.SuspendLayout(); this.panel1.SuspendLayout(); this.panel2.SuspendLayout(); @@ -99,8 +98,7 @@ this.tableLayoutPanel1.Controls.Add(this.rtsys, 0, 0); this.tableLayoutPanel1.Controls.Add(this.rtTx, 2, 0); this.tableLayoutPanel1.Controls.Add(this.panel1, 1, 1); - this.tableLayoutPanel1.Controls.Add(this.panel2, 3, 1); - this.tableLayoutPanel1.Controls.Add(this.panel3, 2, 1); + this.tableLayoutPanel1.Controls.Add(this.panel2, 2, 1); this.tableLayoutPanel1.Controls.Add(this.panel4, 0, 1); this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); @@ -111,45 +109,15 @@ this.tableLayoutPanel1.Size = new System.Drawing.Size(681, 495); this.tableLayoutPanel1.TabIndex = 2; // - // rtAGV + // panel1 // - this.rtAGV.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224))))); - this.rtAGV.ColorList = new arCtl.sLogMessageColor[0]; - this.rtAGV.DateFormat = "mm:ss.fff"; - this.rtAGV.DefaultColor = System.Drawing.Color.LightGray; - this.rtAGV.Dock = System.Windows.Forms.DockStyle.Fill; - this.rtAGV.EnableDisplayTimer = false; - this.rtAGV.EnableGubunColor = true; - this.rtAGV.Font = new System.Drawing.Font("맑은 고딕", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.rtAGV.ListFormat = "[{0}] {1}"; - this.rtAGV.Location = new System.Drawing.Point(0, 14); - this.rtAGV.MaxListCount = ((ushort)(1000)); - this.rtAGV.MaxTextLength = ((uint)(400000u)); - this.rtAGV.MessageInterval = 50; - this.rtAGV.Name = "rtAGV"; - this.rtAGV.Size = new System.Drawing.Size(164, 129); - this.rtAGV.TabIndex = 2; - this.rtAGV.Text = ""; - // - // rtBMS - // - this.rtBMS.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224))))); - this.rtBMS.ColorList = new arCtl.sLogMessageColor[0]; - this.rtBMS.DateFormat = "mm:ss.fff"; - this.rtBMS.DefaultColor = System.Drawing.Color.LightGray; - this.rtBMS.Dock = System.Windows.Forms.DockStyle.Fill; - this.rtBMS.EnableDisplayTimer = false; - this.rtBMS.EnableGubunColor = true; - this.rtBMS.Font = new System.Drawing.Font("맑은 고딕", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.rtBMS.ListFormat = "[{0}] {1}"; - this.rtBMS.Location = new System.Drawing.Point(0, 14); - this.rtBMS.MaxListCount = ((ushort)(1000)); - this.rtBMS.MaxTextLength = ((uint)(400000u)); - this.rtBMS.MessageInterval = 50; - this.rtBMS.Name = "rtBMS"; - this.rtBMS.Size = new System.Drawing.Size(165, 129); - this.rtBMS.TabIndex = 2; - this.rtBMS.Text = ""; + this.panel1.Controls.Add(this.rtXbee); + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(173, 349); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(164, 143); + this.panel1.TabIndex = 3; // // rtXbee // @@ -171,16 +139,6 @@ this.rtXbee.TabIndex = 2; this.rtXbee.Text = ""; // - // panel1 - // - this.panel1.Controls.Add(this.rtXbee); - this.panel1.Controls.Add(this.label1); - this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; - this.panel1.Location = new System.Drawing.Point(173, 349); - this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(164, 143); - this.panel1.TabIndex = 3; - // // label1 // this.label1.Dock = System.Windows.Forms.DockStyle.Top; @@ -193,21 +151,44 @@ // // panel2 // + this.tableLayoutPanel1.SetColumnSpan(this.panel2, 2); this.panel2.Controls.Add(this.rtBMS); this.panel2.Controls.Add(this.label3); this.panel2.Dock = System.Windows.Forms.DockStyle.Fill; - this.panel2.Location = new System.Drawing.Point(513, 349); + this.panel2.Location = new System.Drawing.Point(343, 349); this.panel2.Name = "panel2"; - this.panel2.Size = new System.Drawing.Size(165, 143); + this.panel2.Size = new System.Drawing.Size(335, 143); this.panel2.TabIndex = 4; // - // panel3 + // rtBMS // - this.panel3.Dock = System.Windows.Forms.DockStyle.Fill; - this.panel3.Location = new System.Drawing.Point(343, 349); - this.panel3.Name = "panel3"; - this.panel3.Size = new System.Drawing.Size(164, 143); - this.panel3.TabIndex = 5; + this.rtBMS.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224))))); + this.rtBMS.ColorList = new arCtl.sLogMessageColor[0]; + this.rtBMS.DateFormat = "mm:ss.fff"; + this.rtBMS.DefaultColor = System.Drawing.Color.LightGray; + this.rtBMS.Dock = System.Windows.Forms.DockStyle.Fill; + this.rtBMS.EnableDisplayTimer = false; + this.rtBMS.EnableGubunColor = true; + this.rtBMS.Font = new System.Drawing.Font("맑은 고딕", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.rtBMS.ListFormat = "[{0}] {1}"; + this.rtBMS.Location = new System.Drawing.Point(0, 14); + this.rtBMS.MaxListCount = ((ushort)(1000)); + this.rtBMS.MaxTextLength = ((uint)(400000u)); + this.rtBMS.MessageInterval = 50; + this.rtBMS.Name = "rtBMS"; + this.rtBMS.Size = new System.Drawing.Size(335, 129); + this.rtBMS.TabIndex = 2; + this.rtBMS.Text = ""; + // + // label3 + // + this.label3.Dock = System.Windows.Forms.DockStyle.Top; + this.label3.Location = new System.Drawing.Point(0, 0); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(335, 14); + this.label3.TabIndex = 3; + this.label3.Text = "BMS"; + this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // // panel4 // @@ -219,6 +200,26 @@ this.panel4.Size = new System.Drawing.Size(164, 143); this.panel4.TabIndex = 6; // + // rtAGV + // + this.rtAGV.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224))))); + this.rtAGV.ColorList = new arCtl.sLogMessageColor[0]; + this.rtAGV.DateFormat = "mm:ss.fff"; + this.rtAGV.DefaultColor = System.Drawing.Color.LightGray; + this.rtAGV.Dock = System.Windows.Forms.DockStyle.Fill; + this.rtAGV.EnableDisplayTimer = false; + this.rtAGV.EnableGubunColor = true; + this.rtAGV.Font = new System.Drawing.Font("맑은 고딕", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.rtAGV.ListFormat = "[{0}] {1}"; + this.rtAGV.Location = new System.Drawing.Point(0, 14); + this.rtAGV.MaxListCount = ((ushort)(1000)); + this.rtAGV.MaxTextLength = ((uint)(400000u)); + this.rtAGV.MessageInterval = 50; + this.rtAGV.Name = "rtAGV"; + this.rtAGV.Size = new System.Drawing.Size(164, 129); + this.rtAGV.TabIndex = 2; + this.rtAGV.Text = ""; + // // label2 // this.label2.Dock = System.Windows.Forms.DockStyle.Top; @@ -229,16 +230,6 @@ this.label2.Text = "AGV"; this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // - // label3 - // - this.label3.Dock = System.Windows.Forms.DockStyle.Top; - this.label3.Location = new System.Drawing.Point(0, 0); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(165, 14); - this.label3.TabIndex = 3; - this.label3.Text = "BMS"; - this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - // // fLog // this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F); @@ -269,7 +260,6 @@ private System.Windows.Forms.Panel panel1; private System.Windows.Forms.Label label1; private System.Windows.Forms.Panel panel2; - private System.Windows.Forms.Panel panel3; private System.Windows.Forms.Panel panel4; private System.Windows.Forms.Label label3; private System.Windows.Forms.Label label2; diff --git a/Cs_HMI/Project/StateMachine/_AGV.cs b/Cs_HMI/Project/StateMachine/_AGV.cs index f56ed8d..f8912fa 100644 --- a/Cs_HMI/Project/StateMachine/_AGV.cs +++ b/Cs_HMI/Project/StateMachine/_AGV.cs @@ -106,8 +106,7 @@ namespace Project PUB.log.Add($"충전상태전환 {agv_chg}"); VAR.BOOL[eVarBool.FLAG_CHARGEONA] = agv_chg; } - //자동충전해제시 곧바로 수동 충전되는 경우가 있어 자동 상태를 BMS에 넣는다 230118 - PUB.BMS.AutoCharge = agv_chg; + if (PUB.AGV.error.Charger_pos_error != VAR.BOOL[eVarBool.CHG_POSERR]) { diff --git a/Cs_HMI/Project/StateMachine/_BMS.cs b/Cs_HMI/Project/StateMachine/_BMS.cs index a19c118..4e68f46 100644 --- a/Cs_HMI/Project/StateMachine/_BMS.cs +++ b/Cs_HMI/Project/StateMachine/_BMS.cs @@ -25,15 +25,18 @@ namespace Project DateTime lastbmstime = DateTime.Now; private void Bms_Message(object sender, arDev.BMS.MessageEventArgs e) { - if (e.MsgType == arDev.arRS232.MessageType.Error) PUB.logbms.AddE( e.Message); + + if (e.MsgType == arDev.BMSSerialComm.MessageType.Error) PUB.logbms.AddE(e.Message); else { + VAR.TIME[eVarTime.LastRecv_BAT] = DateTime.Now; + var hexstr = e.Data.GetHexString().Trim(); bool addlog = false; var logtimesec = 30; if (hexstr.StartsWith("DD 04")) { - if (lastbms04.Equals(hexstr.Substring(0,5)) == false) + if (lastbms04.Equals(hexstr.Substring(0, 5)) == false) { addlog = true; lastbms04 = "DD 04"; @@ -133,37 +136,49 @@ namespace Project } } - if(addlog) - PUB.logbms.Add("BMS:" + hexstr); + if (addlog) + { + //if (e.MsgType == arDev.arRS232.MessageType.Recv) + // PUB.logbms.Add("RX", e.Data.GetHexString()); + //else if (e.MsgType == arDev.arRS232.MessageType.Send) + // PUB.logbms.Add("TX", e.Data.GetHexString()); + //else + { + PUB.logbms.Add(e.MsgType.ToString(),e.Message); + } + + } + + } } private void BMS_ChargeDetect(object sender, arDev.ChargetDetectArgs e) { //자동충전중이아니고 멈춰있다면 수동 충전으로 전환한다 - if (PUB.AGV.system1.Battery_charging == false && PUB.AGV.system1.agv_stop == true && VAR.BOOL[eVarBool.FLAG_CHARGEONM] == false) + VAR.TIME[eVarTime.LastRecv_BAT] = DateTime.Now; + if (e.Detected == true) //충전이 감지되었다. { - if (PUB.setting.DetectManualCharge) + if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == false && VAR.BOOL[eVarBool.FLAG_CHARGEONM] == false) { VAR.BOOL[eVarBool.FLAG_CHARGEONM] = true; PUB.Speak(Lang.충전이감지되어수동충전으로전환합니다); + if (PUB.AGV.system1.agv_run == true) PUB.AGV.AGVMoveStop("수동충전감지"); } - else - { - PUB.log.Add($"충전이 감지되었지만 메뉴얼 전환 비활성화됨"); - } - } + else PUB.logbms.AddI("Battery Charge Off"); + } private void Bms_BMSDataReceive(object sender, EventArgs e) { - + + VAR.TIME[eVarTime.LastRecv_BAT] = DateTime.Now; //PUB.mapctl.Manager.agv.BatteryLevel = PUB.BMS.Current_Level; //PUB.mapctl.Manager.agv.BatteryTemp1 = PUB.BMS.Current_temp1; //PUB.mapctl.Manager.agv.BatteryTemp2 = PUB.BMS.Current_temp2; - // [Sync] Update VirtualAGV Battery + // [Sync] Update VirtualAGV Battery PUB.UpdateAGVBattery(PUB.BMS.Current_Level); if (PUB.BMS.Current_Level <= PUB.setting.ChargeStartLevel) @@ -188,6 +203,7 @@ namespace Project } private void BMS_BMSCellDataReceive(object sender, arDev.BMSCelvoltageEventArgs e) { + VAR.TIME[eVarTime.LastRecv_BAT] = DateTime.Now; EEMStatus.MakeBMSInformation_Cell(); } } diff --git a/Cs_HMI/Project/StateMachine/_SPS.cs b/Cs_HMI/Project/StateMachine/_SPS.cs index 4663dbd..2b55fa3 100644 --- a/Cs_HMI/Project/StateMachine/_SPS.cs +++ b/Cs_HMI/Project/StateMachine/_SPS.cs @@ -48,7 +48,7 @@ namespace Project lock (connectobj) { ConnectSerialPort(PUB.XBE, PUB.setting.Port_XBE, PUB.setting.Baud_XBE, - eVarTime.LastConn_XBE, eVarTime.LastConnTry_XBE, eVarTime.LastRecv_XBE); + eVarTime.LastConn_XBE, eVarTime.LastConnTry_XBE, null); } @@ -84,7 +84,6 @@ namespace Project } } - // ========== 2. XBee 상태 전송 ========== if (PUB.XBE != null && PUB.XBE.IsOpen) { @@ -147,7 +146,7 @@ namespace Project /// /// 시리얼 포트 연결 (arDev.arRS232) /// - bool ConnectSerialPort(arDev.ISerialComm dev, string port, int baud, eVarTime conn, eVarTime conntry, eVarTime recvtime) + bool ConnectSerialPort(arDev.ISerialComm dev, string port, int baud, eVarTime conn, eVarTime conntry, eVarTime? recvtime) { if (port.isEmpty()) return false; @@ -159,13 +158,13 @@ namespace Project VAR.TIME.Update(conntry); try { - VAR.TIME.Update(recvtime); + if (recvtime != null) VAR.TIME.Update(recvtime); dev.PortName = port; dev.BaudRate = baud; PUB.log.Add($"Connect to {port}:{baud}"); if (dev.Open()) { - VAR.TIME[recvtime] = DateTime.Now; //값을 수신한것처럼한다 + if (recvtime != null) VAR.TIME[recvtime] = DateTime.Now; //값을 수신한것처럼한다 PUB.log.Add(port, $"[{port}:{baud}] 연결 완료"); } else @@ -202,7 +201,7 @@ namespace Project VAR.TIME.Update(conntry); } - else if (dev.IsOpen) + else if (dev.IsOpen && recvtime != null) { //연결은 되었으나 통신이 지난지 10초가 지났다면 자동종료한다 var tsRecv = VAR.TIME.RUN(recvtime); diff --git a/Cs_HMI/Project/fMain.cs b/Cs_HMI/Project/fMain.cs index 62b90eb..9a868be 100644 --- a/Cs_HMI/Project/fMain.cs +++ b/Cs_HMI/Project/fMain.cs @@ -56,7 +56,7 @@ namespace Project if (DateTime.Now > PUB.LastInputTime) PUB.LastInputTime = DateTime.Now; }; - + PUB._mapCanvas = new AGVNavigationCore.Controls.UnifiedAGVCanvas(); PUB._mapCanvas.Dock = DockStyle.Fill; PUB._mapCanvas.ShowGrid = false; @@ -75,7 +75,7 @@ namespace Project } - + private void __Closing(object sender, FormClosingEventArgs e) { // 장치 관리 태스크는 _STEP_CLOSING_START에서 종료됨 @@ -250,7 +250,7 @@ namespace Project //수량표시 PUB.counter.PropertyChanged += (s1, e1) => Update_Count(); Update_Count(); - + PUB.log.Add("프로그램 실행 기록 추가"); PUB.CheckNRegister3(Application.ProductName, "chi", Application.ProductVersion); @@ -780,6 +780,12 @@ namespace Project { if (VAR.BOOL[eVarBool.FLAG_CHARGEONM]) { + if (PUB.BMS.IsValid && PUB.BMS.IsCharging) + { + UTIL.MsgE("현재 배터리에서 충전 상태가 감지되고 있어 해제할 수 없습니다"); + return; + } + var dlg = UTIL.MsgQ("수동 충전을 해제 할까요?"); if (dlg != DialogResult.Yes) return; VAR.BOOL[eVarBool.FLAG_CHARGEONM] = false; @@ -889,7 +895,7 @@ namespace Project } var _mapCanvas = PUB._mapCanvas; - + // 🔥 현재 캔버스 설정을 맵 파일에 저장 var settings = new MapLoader.MapSettings diff --git a/Cs_HMI/StateMachine/StateMachine.cs b/Cs_HMI/StateMachine/StateMachine.cs index 414afbd..ab99c48 100644 --- a/Cs_HMI/StateMachine/StateMachine.cs +++ b/Cs_HMI/StateMachine/StateMachine.cs @@ -256,11 +256,8 @@ namespace Project.StateMachine if (handler != null) { var args = new StepChangeEventArgs(OldStep, newstep_); - System.Threading.ThreadPool.QueueUserWorkItem(_ => - { - try { handler(this, args); } - catch { /* 이벤트 핸들러 예외 무시 */ } - }); + try { handler(this, args); } + catch { /* 이벤트 핸들러 예외 무시 */ } } } else @@ -378,11 +375,8 @@ namespace Project.StateMachine if (handler != null) { var args = new StepChangeEventArgs(ostep, _step); - System.Threading.ThreadPool.QueueUserWorkItem(_ => - { - try { handler(this, args); } - catch { /* 이벤트 핸들러 예외 무시 */ } - }); + try { handler(this, args); } + catch { /* 이벤트 핸들러 예외 무시 */ } } } //171214 diff --git a/Cs_HMI/SubProject/AGV/NarumiSerialComm.cs b/Cs_HMI/SubProject/AGV/NarumiSerialComm.cs index 23f26a9..370960b 100644 --- a/Cs_HMI/SubProject/AGV/NarumiSerialComm.cs +++ b/Cs_HMI/SubProject/AGV/NarumiSerialComm.cs @@ -107,7 +107,7 @@ namespace arDev public NarumiSerialComm() { _device = new System.IO.Ports.SerialPort(); - this.BaudRate = 9600; + this.BaudRate = 57600; ScanInterval = 10; // _device.DataReceived += barcode_DataReceived; // Removed event handler _device.ErrorReceived += this.barcode_ErrorReceived;