From 671d6545a3764629fbce28c7d23cbb9880b6d734 Mon Sep 17 00:00:00 2001 From: jkwoo Date: Wed, 17 Dec 2025 14:22:17 +0900 Subject: [PATCH] - 1.0.1.7 - 2025/12/17 * 124V RS-485 Thread Improved --- LFP_Manager/Threads/CsRs485Thread124050.cs | 521 +++++++++++---------- 1 file changed, 276 insertions(+), 245 deletions(-) diff --git a/LFP_Manager/Threads/CsRs485Thread124050.cs b/LFP_Manager/Threads/CsRs485Thread124050.cs index abadab4..6c963eb 100644 --- a/LFP_Manager/Threads/CsRs485Thread124050.cs +++ b/LFP_Manager/Threads/CsRs485Thread124050.cs @@ -1,13 +1,12 @@ -using System; - -using System.Threading; -using System.IO.Ports; -using System.Windows.Forms; - +using DevExpress.XtraGauges.Core.Model; using LFP_Manager.DataStructure; using LFP_Manager.Function; using LFP_Manager.Utils; -using DevExpress.XtraGauges.Core.Model; +using System; +using System.IO.Ports; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; namespace LFP_Manager.Threads { @@ -17,9 +16,10 @@ namespace LFP_Manager.Threads private readonly CommConfig Config; private DeviceSystemData[] SystemData; - private Thread serialComm = null; + private Task serialCommTask = null; + private CancellationTokenSource _cts; private SerialPort sPort = null; - private bool SerialPortThreadEnd = true; + private volatile bool SerialPortThreadEnd = true; public int ModuleID = 1; private bool UartPolling = false; @@ -28,7 +28,7 @@ namespace LFP_Manager.Threads private int addr_ch = 0; private ushort RequestRegAddr = 0x0000; //Byul Init 0x0000 private ushort RequestRegLen = 50; - private bool rFlag = false; + private volatile bool rFlag = false; private int wFlag = 0; private int rFlag2 = 0; @@ -56,29 +56,20 @@ namespace LFP_Manager.Threads SystemData = aSystemData; UartTxBuff = new TUartTxBuff(); - - serialComm = new Thread(uartCommThread); + _cts = new CancellationTokenSource(); } public void disposeThread() { - if (sPort != null) + try { - if (sPort.IsOpen) - { - sPort.Close(); - } - sPort = null; - } - SerialPortThreadEnd = true; - if (serialComm != null) - { - if (serialComm.IsAlive) - { - serialComm.Abort(); - } - serialComm = null; + Stop(); } + catch { } + + Close(); + _cts?.Dispose(); + _cts = null; } public bool Start(ref CommConfig aConfig, int mID, bool aPolling) @@ -88,10 +79,15 @@ namespace LFP_Manager.Threads ModuleID = mID; UartPolling = aPolling; - if (Open(aConfig.UartPort, 9600)) //Byul Init 9600 + // Port open with configured baudrate (fallback to 9600) + int baud = (aConfig?.UartBaudrate > 0) ? aConfig.UartBaudrate : 9600; + if (Open(aConfig.UartPort, baud)) { SerialPortThreadEnd = false; - serialComm.Start(); + // recreate CTS for this run + _cts?.Dispose(); + _cts = new CancellationTokenSource(); + serialCommTask = Task.Run(() => uartCommThread(_cts.Token), _cts.Token); result = true; } return result; @@ -99,38 +95,57 @@ namespace LFP_Manager.Threads public void Stop() { - SerialPortThreadEnd = true; - Close(); + try + { + SerialPortThreadEnd = true; + if (_cts != null && !_cts.IsCancellationRequested) + _cts.Cancel(); + + serialCommTask?.Wait(TimeSpan.FromSeconds(5)); + } + catch (AggregateException) { } + catch (OperationCanceledException) { } + catch { } + finally + { + Close(); + } } #endregion #region COMMPORT CONTROLS + private readonly object _rxLock = new object(); + private readonly object _portLock = new object(); + private void sDataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { - byte[] sRead = new byte[1024]; - int rLen = 0; - try { - rLen = ((SerialPort)sender).Read(sRead, 0, 1024); + if (sPort == null || !sPort.IsOpen) return; - for (int i = 0; i < rLen; i++) + byte[] sRead = new byte[1024]; + int rLen = sPort.Read(sRead, 0, sRead.Length); + + lock (_rxLock) { - PutBuff(sRead[i]); + for (int i = 0; i < rLen; i++) + { + PutBuff(sRead[i]); + } } } - catch (Exception) + catch (Exception ex) { - + // 무시하지 말고 로그 출력 + OnPrint?.Invoke(this, $"DataRecv Error: {ex.Message}"); } } private void sErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e) { - // - //csMakeDataFunction.SetData() + OnPrint?.Invoke(this, $"Serial Error: {e.EventType}"); } private void sPinChanged(object sender, System.IO.Ports.SerialPinChangedEventArgs e) @@ -140,34 +155,73 @@ namespace LFP_Manager.Threads private bool Open(string cPort, int cBaudrate) { - sPort = new SerialPort(); - sPort.PortName = cPort; - sPort.BaudRate = cBaudrate; - sPort.DataReceived += sDataReceived; - sPort.ErrorReceived += sErrorReceived; - sPort.PinChanged += sPinChanged; - - try + lock (_portLock) { - sPort.Open(); - } - catch (Exception ex) - { - throw new Exception("Error Open - " + ex.Message); - } + try + { + if (sPort != null) + { + if (sPort.IsOpen) sPort.Close(); + sPort.Dispose(); + sPort = null; + } - return sPort.IsOpen; + sPort = new SerialPort + { + PortName = cPort, + BaudRate = cBaudrate, + DataBits = 8, + Parity = Parity.None, + StopBits = StopBits.One, + ReadTimeout = 500, + WriteTimeout = 500 + }; + + sPort.DataReceived += sDataReceived; + sPort.ErrorReceived += sErrorReceived; + sPort.PinChanged += sPinChanged; + + sPort.Open(); + return sPort.IsOpen; + } + catch (Exception ex) + { + OnPrint?.Invoke(this, $"Error Open - {ex.Message}"); + if (sPort != null) + { + try { sPort.Dispose(); } catch { } + sPort = null; + } + return false; + } + } } private void Close() { - if (sPort != null) + lock (_portLock) { - if (sPort.IsOpen) + try { - sPort.Close(); + if (sPort != null) + { + try + { + sPort.DataReceived -= sDataReceived; + sPort.ErrorReceived -= sErrorReceived; + sPort.PinChanged -= sPinChanged; + } + catch { } + + if (sPort.IsOpen) sPort.Close(); + sPort.Dispose(); + sPort = null; + } + } + catch (Exception ex) + { + OnPrint?.Invoke(this, $"Port Close Fail: {ex.Message}"); } - sPort = null; } } @@ -180,7 +234,8 @@ namespace LFP_Manager.Threads ModuleID = mID; UartPolling = flag; SystemData = aSystemData; - SystemData[ModuleID - 1].mNo = ModuleID; + if (SystemData != null && ModuleID - 1 >= 0 && ModuleID - 1 < SystemData.Length) + SystemData[ModuleID - 1].mNo = ModuleID; } public void SetAutoTx(bool autoTx) @@ -188,27 +243,16 @@ namespace LFP_Manager.Threads AutoUartTx = autoTx; } - public void SetWriteCoilReg(ushort WriteAddr, short WriteData) - { - wFlag = 2; - WriteRegAddr = WriteAddr; - WriteCoilRegData = WriteData; - - for (int i = 0; i < 500; i += 10) - { - Thread.Sleep(10); - Application.DoEvents(); - } - } public void SetWriteReg(ushort WriteAddr, byte[] WriteData, bool ReplyFlag, int type) { WriteRegAddr = WriteAddr; - TUartTRxData uartTRxData = new TUartTRxData(); - uartTRxData.type = type; - //uartTRxData.data = CsRs485CommFunction124050.MakeWriteRegisterData((ushort)ModuleID, WriteRegAddr, WriteData); - uartTRxData.data = WriteData; - uartTRxData.length = uartTRxData.data.Length; + var uartTRxData = new TUartTRxData + { + type = type, + data = WriteData, + length = WriteData?.Length ?? 0 + }; UartTxBuff?.PutBuff(uartTRxData); } @@ -219,10 +263,7 @@ namespace LFP_Manager.Threads if (sData != null) { - TUartTRxData aData = new TUartTRxData(); - aData.length = sData.Length; - aData.data = sData; - + var aData = new TUartTRxData { length = sData.Length, data = sData }; UartTxBuff.PutBuff(aData); } } @@ -233,12 +274,8 @@ namespace LFP_Manager.Threads if (sData != null) { - TUartTRxData aData = new TUartTRxData(); - aData.length = sData.Length; - aData.data = sData; - + var aData = new TUartTRxData { length = sData.Length, data = sData }; ExtReqRegAddr = WriteAddr; - UartTxBuff.PutBuff(aData); } } @@ -255,66 +292,47 @@ namespace LFP_Manager.Threads private void PutBuff(byte c) { - rBuffer[rBufStart++] = c; - rBufStart %= BUFFER_SIZE; - - if (rBufStart == rBufEnd) + // called from DataReceived event -> lock to be safe + lock (_rxLock) { - rBufEnd++; - rBufEnd %= BUFFER_SIZE; + rBuffer[rBufStart++] = c; + rBufStart %= BUFFER_SIZE; + + if (rBufStart == rBufEnd) + { + rBufEnd++; + rBufEnd %= BUFFER_SIZE; + } } } private int GetBuff() { - int result = 0; - - if (rBufStart != rBufEnd) + lock (_rxLock) { - result = 0x0100 + rBuffer[rBufEnd++]; - rBufEnd %= BUFFER_SIZE; + int result = -1; + + if (rBufStart != rBufEnd) + { + result = 0x0100 + rBuffer[rBufEnd++]; + rBufEnd %= BUFFER_SIZE; + } + return result; } - return result; } private void FlushBuff() { - rBufStart = rBufEnd = 0; + lock (_rxLock) + { + rBufStart = rBufEnd = 0; + } } #endregion #region TX BUFFERING - private byte[] MakeWriteRegData(ushort DevID, ushort WriteAddr, ushort WriteLen, ref ushort[] WriteData) - { - byte[] wData = null; - - if (WriteLen > 0) - { - - } - - return wData; - } - - private string MakeCheckSum(byte[] sData, int len) - { - string result = ""; - int checksum = 0; - - for (int i = 0; i < len; i++) - { - checksum += sData[i + 1]; - } - - checksum = ~checksum + 1; - - result = String.Format("{0:X2}{1:X2}", (byte)(checksum >> 8), (byte)checksum); - - return result; - } - private byte[] MakeTxDataDelta(bool wData) { byte[] sData = null; @@ -360,13 +378,6 @@ namespace LFP_Manager.Threads sCmd = CsSerialCommFunctionDelta.READ_INPUT_REG; // Command 0x19 rFlag = true; break; - //case 3: - // addr_ch = 4; - // RequestRegAddr = 0x0000; - // RequestRegLen = 1; - // sCmd = CsSerialCommFunctionDelta.READ_DEV_ID; // Command 0x2B - // rFlag = true; - // break; case 3: addr_ch = 4; RequestRegAddr = 100; @@ -389,9 +400,9 @@ namespace LFP_Manager.Threads break; default: addr_ch = 0; - RequestRegAddr = 0x0FFF; //Byul Init 0x0000 + RequestRegAddr = 0x0FFF; RequestRegLen = 27; - sCmd = CsSerialCommFunctionDelta.READ_INPUT_REG; // Command 0x04 + sCmd = CsSerialCommFunctionDelta.READ_INPUT_REG; rFlag = true; break; } @@ -426,140 +437,160 @@ namespace LFP_Manager.Threads rPosition = 0; } - private void uartCommThread() + private void uartCommThread(CancellationToken token) { - int RecvTimeout = Config.RecvWaitTime; - int getData = 0; - byte cData = 0; - int[] TimeOutCount = new int[csConstData.SystemInfo.MAX_MODULE_SIZE]; - - StartSend: - while (SerialPortThreadEnd == false) + try { - if ((sPort == null) || (sPort.IsOpen == false)) continue; + int RecvTimeout = (Config != null) ? Config.RecvWaitTime : 1500; + int getData = 0; + byte cData = 0; + int[] TimeOutCount = new int[csConstData.SystemInfo.MAX_MODULE_SIZE]; - FlushBuff(); - byte[] txData = MakeTxDataDelta(false); - if (sPort == null) return; - if (txData != null) + StartSend: + while (!token.IsCancellationRequested && SerialPortThreadEnd == false) { - sPort.Write(txData, 0, txData.Length); - OnPrint?.Invoke(this, csLog.trx_data_print(txData, txData.Length, 0)); - } - - if (rFlag == true) - { - DateTime rDateTime = DateTime.Now; - - RecvPacketInit(); - - while (true) + if ((sPort == null) || (sPort.IsOpen == false)) { - DateTime nDateTime = rDateTime.AddMilliseconds(RecvTimeout); - if (nDateTime < DateTime.Now) break; + Thread.Sleep(100); + continue; + } - if (((getData = GetBuff()) & 0x0100) != 0x0000) + FlushBuff(); + byte[] txData = MakeTxDataDelta(false); + if (sPort == null) return; + if (txData != null) + { + try { - rDateTime = DateTime.Now; + sPort.Write(txData, 0, txData.Length); + OnPrint?.Invoke(this, csLog.trx_data_print(txData, txData.Length, 0)); + } + catch (Exception ex) + { + OnPrint?.Invoke(this, $"Write error: {ex.Message}"); + } + } - cData = (byte)(getData & 0x00FF); + if (rFlag == true) + { + DateTime rDateTime = DateTime.Now; - if (rPosition >= BUFFER_SIZE) RecvPacketInit(); + RecvPacketInit(); - if (BuffStart == false) + while (!token.IsCancellationRequested) + { + DateTime nDateTime = rDateTime.AddMilliseconds(RecvTimeout); + if (nDateTime < DateTime.Now) break; + + getData = GetBuff(); + if ((getData & 0x0100) != 0x0000) { - if ((cData == (byte)ModuleID) || (cData == (byte)0x7F)) + rDateTime = DateTime.Now; + + cData = (byte)(getData & 0x00FF); + + if (rPosition >= BUFFER_SIZE) RecvPacketInit(); + + if (!BuffStart) { - rPosition = 0; - ReadBuf[rPosition++] = cData; - BuffStart = true; + if ((cData == (byte)ModuleID) || (cData == (byte)0x7F)) + { + rPosition = 0; + ReadBuf[rPosition++] = cData; + BuffStart = true; + } } + else + { + ReadBuf[rPosition++] = cData; + + int chk = CsRs485CommFunction124050.ModbusPacketFromSlaveCheck(ReadBuf, rPosition); + switch (chk) + { + case 0: // Need more data + break; + case 1: // Packet OK, no error + OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1)); + + TimeOutCount[ModuleID - 1] = 0; + + int mID = ReadBuf[0]; + if (mID > 0) mID--; + + SystemData[mID].CommFail = false; + SystemData[mID].ShelfCommFail = false; + short[] result_code = CsRs485CommFunction124050.SerialRxProcess(ReadBuf, RequestRegAddr, rPosition, ref SystemData[mID]); + + OnUpdate?.Invoke(this, ref SystemData); + + Thread.Sleep(5); + goto StartSend; + case 2: // Fw Update Packet OK + OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1)); + + TimeOutCount[ModuleID - 1] = 0; + rFlag = false; + if (OnDataRecv != null) + { + var adata = new byte[rPosition]; + Array.Copy(ReadBuf, 0, adata, 0, rPosition); + OnDataRecv(adata); + } + goto StartSend; + case -1: // Packet error + RecvPacketInit(); + Thread.Sleep(100); + goto StartSend; + default: + break; + } + } + Thread.Sleep(1); } else { - ReadBuf[rPosition++] = cData; - - switch (CsRs485CommFunction124050.ModbusPacketFromSlaveCheck(ReadBuf, rPosition)) - { - case 0: // Need more data - break; - case 1: // Packet OK, no error - OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1)); - - TimeOutCount[ModuleID - 1] = 0; - - int mID = ReadBuf[0]; - if (mID > 0) mID--; - - SystemData[mID].CommFail = false; - SystemData[mID].ShelfCommFail = false; - short[] result_code = CsRs485CommFunction124050.SerialRxProcess(ReadBuf, RequestRegAddr, rPosition, ref SystemData[mID]); - - OnUpdate?.Invoke(this, ref SystemData); - - Thread.Sleep(5); - goto StartSend; - case 2: // Fw Update Packet OK - OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1)); - - TimeOutCount[ModuleID - 1] = 0; - rFlag = false; - if (OnDataRecv != null) - { - byte[] adata = new byte[rPosition + 1]; - for (int j = 0; j < adata.Length; j++) - { - adata[j] = ReadBuf[j]; - } - OnDataRecv(adata); - } - goto StartSend; - case -1: // Packet error - RecvPacketInit(); - Thread.Sleep(100); - goto StartSend; - default: - break; - } + Thread.Sleep(1); } + } + + if (rPosition > 0) + { + OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1)); Thread.Sleep(1); } else { - Thread.Sleep(1); + TimeOutCount[ModuleID - 1]++; + if (TimeOutCount[ModuleID - 1] >= 10) + { + TimeOutCount[ModuleID - 1] = 10; + if (SystemData[ModuleID - 1].ShelfCommFail == false) + { + SystemData[ModuleID - 1].ShelfCommFail = true; + csUtils.DataInit(Config, ref SystemData[ModuleID - 1]); + } + } + Thread.Sleep(100); } - } - - if (rPosition > 0) - { - OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1)); - + OnUpdate?.Invoke(this, ref SystemData); Thread.Sleep(1); } else { - TimeOutCount[ModuleID - 1]++; - if (TimeOutCount[ModuleID - 1] >= 10) - { - TimeOutCount[ModuleID - 1] = 10; - //SystemData[0].CommFail = true; - if (SystemData[ModuleID - 1].ShelfCommFail == false) - { - SystemData[ModuleID - 1].ShelfCommFail = true; - csUtils.DataInit(Config, ref SystemData[ModuleID - 1]); - } - } - Thread.Sleep(100); - } - OnUpdate?.Invoke(this, ref SystemData); - Thread.Sleep(1); + Thread.Sleep(10); + } /* if (rFlag == true) */ + rPosition = 0; + Thread.Sleep(100); } - else - { - Thread.Sleep(10); - } /* if (rFlag == true) */ - rPosition = 0; - Thread.Sleep(100); + } + catch (OperationCanceledException) { } + catch (Exception ex) + { + OnPrint?.Invoke(this, $"Comm thread error: {ex.Message}"); + } + finally + { + SerialPortThreadEnd = true; } }