- 1.0.1.7 - 2025/12/17

* 124V RS-485 Thread Improved
This commit is contained in:
2025-12-17 14:22:17 +09:00
parent 368acb1aa8
commit 671d6545a3

View File

@@ -1,13 +1,12 @@
using System; using DevExpress.XtraGauges.Core.Model;
using System.Threading;
using System.IO.Ports;
using System.Windows.Forms;
using LFP_Manager.DataStructure; using LFP_Manager.DataStructure;
using LFP_Manager.Function; using LFP_Manager.Function;
using LFP_Manager.Utils; 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 namespace LFP_Manager.Threads
{ {
@@ -17,9 +16,10 @@ namespace LFP_Manager.Threads
private readonly CommConfig Config; private readonly CommConfig Config;
private DeviceSystemData[] SystemData; private DeviceSystemData[] SystemData;
private Thread serialComm = null; private Task serialCommTask = null;
private CancellationTokenSource _cts;
private SerialPort sPort = null; private SerialPort sPort = null;
private bool SerialPortThreadEnd = true; private volatile bool SerialPortThreadEnd = true;
public int ModuleID = 1; public int ModuleID = 1;
private bool UartPolling = false; private bool UartPolling = false;
@@ -28,7 +28,7 @@ namespace LFP_Manager.Threads
private int addr_ch = 0; private int addr_ch = 0;
private ushort RequestRegAddr = 0x0000; //Byul Init 0x0000 private ushort RequestRegAddr = 0x0000; //Byul Init 0x0000
private ushort RequestRegLen = 50; private ushort RequestRegLen = 50;
private bool rFlag = false; private volatile bool rFlag = false;
private int wFlag = 0; private int wFlag = 0;
private int rFlag2 = 0; private int rFlag2 = 0;
@@ -56,29 +56,20 @@ namespace LFP_Manager.Threads
SystemData = aSystemData; SystemData = aSystemData;
UartTxBuff = new TUartTxBuff(); UartTxBuff = new TUartTxBuff();
_cts = new CancellationTokenSource();
serialComm = new Thread(uartCommThread);
} }
public void disposeThread() public void disposeThread()
{ {
if (sPort != null) try
{ {
if (sPort.IsOpen) Stop();
{
sPort.Close();
}
sPort = null;
}
SerialPortThreadEnd = true;
if (serialComm != null)
{
if (serialComm.IsAlive)
{
serialComm.Abort();
}
serialComm = null;
} }
catch { }
Close();
_cts?.Dispose();
_cts = null;
} }
public bool Start(ref CommConfig aConfig, int mID, bool aPolling) public bool Start(ref CommConfig aConfig, int mID, bool aPolling)
@@ -88,49 +79,73 @@ namespace LFP_Manager.Threads
ModuleID = mID; ModuleID = mID;
UartPolling = aPolling; 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; SerialPortThreadEnd = false;
serialComm.Start(); // recreate CTS for this run
_cts?.Dispose();
_cts = new CancellationTokenSource();
serialCommTask = Task.Run(() => uartCommThread(_cts.Token), _cts.Token);
result = true; result = true;
} }
return result; return result;
} }
public void Stop() public void Stop()
{
try
{ {
SerialPortThreadEnd = true; SerialPortThreadEnd = true;
if (_cts != null && !_cts.IsCancellationRequested)
_cts.Cancel();
serialCommTask?.Wait(TimeSpan.FromSeconds(5));
}
catch (AggregateException) { }
catch (OperationCanceledException) { }
catch { }
finally
{
Close(); Close();
} }
}
#endregion #endregion
#region COMMPORT CONTROLS #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) private void sDataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{ {
byte[] sRead = new byte[1024];
int rLen = 0;
try try
{ {
rLen = ((SerialPort)sender).Read(sRead, 0, 1024); if (sPort == null || !sPort.IsOpen) return;
byte[] sRead = new byte[1024];
int rLen = sPort.Read(sRead, 0, sRead.Length);
lock (_rxLock)
{
for (int i = 0; i < rLen; i++) for (int i = 0; i < rLen; i++)
{ {
PutBuff(sRead[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) private void sErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
{ {
// OnPrint?.Invoke(this, $"Serial Error: {e.EventType}");
//csMakeDataFunction.SetData()
} }
private void sPinChanged(object sender, System.IO.Ports.SerialPinChangedEventArgs e) private void sPinChanged(object sender, System.IO.Ports.SerialPinChangedEventArgs e)
@@ -140,36 +155,75 @@ namespace LFP_Manager.Threads
private bool Open(string cPort, int cBaudrate) private bool Open(string cPort, int cBaudrate)
{ {
sPort = new SerialPort(); lock (_portLock)
sPort.PortName = cPort; {
sPort.BaudRate = cBaudrate; try
{
if (sPort != null)
{
if (sPort.IsOpen) sPort.Close();
sPort.Dispose();
sPort = null;
}
sPort = new SerialPort
{
PortName = cPort,
BaudRate = cBaudrate,
DataBits = 8,
Parity = Parity.None,
StopBits = StopBits.One,
ReadTimeout = 500,
WriteTimeout = 500
};
sPort.DataReceived += sDataReceived; sPort.DataReceived += sDataReceived;
sPort.ErrorReceived += sErrorReceived; sPort.ErrorReceived += sErrorReceived;
sPort.PinChanged += sPinChanged; sPort.PinChanged += sPinChanged;
try
{
sPort.Open(); sPort.Open();
return sPort.IsOpen;
} }
catch (Exception ex) catch (Exception ex)
{ {
throw new Exception("Error Open - " + ex.Message); OnPrint?.Invoke(this, $"Error Open - {ex.Message}");
if (sPort != null)
{
try { sPort.Dispose(); } catch { }
sPort = null;
}
return false;
}
} }
return sPort.IsOpen;
} }
private void Close() private void Close()
{
lock (_portLock)
{
try
{ {
if (sPort != null) if (sPort != null)
{ {
if (sPort.IsOpen) try
{ {
sPort.Close(); sPort.DataReceived -= sDataReceived;
sPort.ErrorReceived -= sErrorReceived;
sPort.PinChanged -= sPinChanged;
} }
catch { }
if (sPort.IsOpen) sPort.Close();
sPort.Dispose();
sPort = null; sPort = null;
} }
} }
catch (Exception ex)
{
OnPrint?.Invoke(this, $"Port Close Fail: {ex.Message}");
}
}
}
#endregion #endregion
@@ -180,6 +234,7 @@ namespace LFP_Manager.Threads
ModuleID = mID; ModuleID = mID;
UartPolling = flag; UartPolling = flag;
SystemData = aSystemData; SystemData = aSystemData;
if (SystemData != null && ModuleID - 1 >= 0 && ModuleID - 1 < SystemData.Length)
SystemData[ModuleID - 1].mNo = ModuleID; SystemData[ModuleID - 1].mNo = ModuleID;
} }
@@ -188,27 +243,16 @@ namespace LFP_Manager.Threads
AutoUartTx = autoTx; 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) public void SetWriteReg(ushort WriteAddr, byte[] WriteData, bool ReplyFlag, int type)
{ {
WriteRegAddr = WriteAddr; WriteRegAddr = WriteAddr;
TUartTRxData uartTRxData = new TUartTRxData(); var uartTRxData = new TUartTRxData
uartTRxData.type = type; {
//uartTRxData.data = CsRs485CommFunction124050.MakeWriteRegisterData((ushort)ModuleID, WriteRegAddr, WriteData); type = type,
uartTRxData.data = WriteData; data = WriteData,
uartTRxData.length = uartTRxData.data.Length; length = WriteData?.Length ?? 0
};
UartTxBuff?.PutBuff(uartTRxData); UartTxBuff?.PutBuff(uartTRxData);
} }
@@ -219,10 +263,7 @@ namespace LFP_Manager.Threads
if (sData != null) if (sData != null)
{ {
TUartTRxData aData = new TUartTRxData(); var aData = new TUartTRxData { length = sData.Length, data = sData };
aData.length = sData.Length;
aData.data = sData;
UartTxBuff.PutBuff(aData); UartTxBuff.PutBuff(aData);
} }
} }
@@ -233,12 +274,8 @@ namespace LFP_Manager.Threads
if (sData != null) if (sData != null)
{ {
TUartTRxData aData = new TUartTRxData(); var aData = new TUartTRxData { length = sData.Length, data = sData };
aData.length = sData.Length;
aData.data = sData;
ExtReqRegAddr = WriteAddr; ExtReqRegAddr = WriteAddr;
UartTxBuff.PutBuff(aData); UartTxBuff.PutBuff(aData);
} }
} }
@@ -254,6 +291,9 @@ namespace LFP_Manager.Threads
private int rBufEnd = 0; private int rBufEnd = 0;
private void PutBuff(byte c) private void PutBuff(byte c)
{
// called from DataReceived event -> lock to be safe
lock (_rxLock)
{ {
rBuffer[rBufStart++] = c; rBuffer[rBufStart++] = c;
rBufStart %= BUFFER_SIZE; rBufStart %= BUFFER_SIZE;
@@ -264,10 +304,13 @@ namespace LFP_Manager.Threads
rBufEnd %= BUFFER_SIZE; rBufEnd %= BUFFER_SIZE;
} }
} }
}
private int GetBuff() private int GetBuff()
{ {
int result = 0; lock (_rxLock)
{
int result = -1;
if (rBufStart != rBufEnd) if (rBufStart != rBufEnd)
{ {
@@ -276,45 +319,20 @@ namespace LFP_Manager.Threads
} }
return result; return result;
} }
}
private void FlushBuff() private void FlushBuff()
{
lock (_rxLock)
{ {
rBufStart = rBufEnd = 0; rBufStart = rBufEnd = 0;
} }
}
#endregion #endregion
#region TX BUFFERING #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) private byte[] MakeTxDataDelta(bool wData)
{ {
byte[] sData = null; byte[] sData = null;
@@ -360,13 +378,6 @@ namespace LFP_Manager.Threads
sCmd = CsSerialCommFunctionDelta.READ_INPUT_REG; // Command 0x19 sCmd = CsSerialCommFunctionDelta.READ_INPUT_REG; // Command 0x19
rFlag = true; rFlag = true;
break; break;
//case 3:
// addr_ch = 4;
// RequestRegAddr = 0x0000;
// RequestRegLen = 1;
// sCmd = CsSerialCommFunctionDelta.READ_DEV_ID; // Command 0x2B
// rFlag = true;
// break;
case 3: case 3:
addr_ch = 4; addr_ch = 4;
RequestRegAddr = 100; RequestRegAddr = 100;
@@ -389,9 +400,9 @@ namespace LFP_Manager.Threads
break; break;
default: default:
addr_ch = 0; addr_ch = 0;
RequestRegAddr = 0x0FFF; //Byul Init 0x0000 RequestRegAddr = 0x0FFF;
RequestRegLen = 27; RequestRegLen = 27;
sCmd = CsSerialCommFunctionDelta.READ_INPUT_REG; // Command 0x04 sCmd = CsSerialCommFunctionDelta.READ_INPUT_REG;
rFlag = true; rFlag = true;
break; break;
} }
@@ -426,26 +437,39 @@ namespace LFP_Manager.Threads
rPosition = 0; rPosition = 0;
} }
private void uartCommThread() private void uartCommThread(CancellationToken token)
{ {
int RecvTimeout = Config.RecvWaitTime; try
{
int RecvTimeout = (Config != null) ? Config.RecvWaitTime : 1500;
int getData = 0; int getData = 0;
byte cData = 0; byte cData = 0;
int[] TimeOutCount = new int[csConstData.SystemInfo.MAX_MODULE_SIZE]; int[] TimeOutCount = new int[csConstData.SystemInfo.MAX_MODULE_SIZE];
StartSend: StartSend:
while (SerialPortThreadEnd == false) while (!token.IsCancellationRequested && SerialPortThreadEnd == false)
{ {
if ((sPort == null) || (sPort.IsOpen == false)) continue; if ((sPort == null) || (sPort.IsOpen == false))
{
Thread.Sleep(100);
continue;
}
FlushBuff(); FlushBuff();
byte[] txData = MakeTxDataDelta(false); byte[] txData = MakeTxDataDelta(false);
if (sPort == null) return; if (sPort == null) return;
if (txData != null) if (txData != null)
{
try
{ {
sPort.Write(txData, 0, txData.Length); sPort.Write(txData, 0, txData.Length);
OnPrint?.Invoke(this, csLog.trx_data_print(txData, txData.Length, 0)); OnPrint?.Invoke(this, csLog.trx_data_print(txData, txData.Length, 0));
} }
catch (Exception ex)
{
OnPrint?.Invoke(this, $"Write error: {ex.Message}");
}
}
if (rFlag == true) if (rFlag == true)
{ {
@@ -453,12 +477,13 @@ namespace LFP_Manager.Threads
RecvPacketInit(); RecvPacketInit();
while (true) while (!token.IsCancellationRequested)
{ {
DateTime nDateTime = rDateTime.AddMilliseconds(RecvTimeout); DateTime nDateTime = rDateTime.AddMilliseconds(RecvTimeout);
if (nDateTime < DateTime.Now) break; if (nDateTime < DateTime.Now) break;
if (((getData = GetBuff()) & 0x0100) != 0x0000) getData = GetBuff();
if ((getData & 0x0100) != 0x0000)
{ {
rDateTime = DateTime.Now; rDateTime = DateTime.Now;
@@ -466,7 +491,7 @@ namespace LFP_Manager.Threads
if (rPosition >= BUFFER_SIZE) RecvPacketInit(); if (rPosition >= BUFFER_SIZE) RecvPacketInit();
if (BuffStart == false) if (!BuffStart)
{ {
if ((cData == (byte)ModuleID) || (cData == (byte)0x7F)) if ((cData == (byte)ModuleID) || (cData == (byte)0x7F))
{ {
@@ -479,7 +504,8 @@ namespace LFP_Manager.Threads
{ {
ReadBuf[rPosition++] = cData; ReadBuf[rPosition++] = cData;
switch (CsRs485CommFunction124050.ModbusPacketFromSlaveCheck(ReadBuf, rPosition)) int chk = CsRs485CommFunction124050.ModbusPacketFromSlaveCheck(ReadBuf, rPosition);
switch (chk)
{ {
case 0: // Need more data case 0: // Need more data
break; break;
@@ -506,11 +532,8 @@ namespace LFP_Manager.Threads
rFlag = false; rFlag = false;
if (OnDataRecv != null) if (OnDataRecv != null)
{ {
byte[] adata = new byte[rPosition + 1]; var adata = new byte[rPosition];
for (int j = 0; j < adata.Length; j++) Array.Copy(ReadBuf, 0, adata, 0, rPosition);
{
adata[j] = ReadBuf[j];
}
OnDataRecv(adata); OnDataRecv(adata);
} }
goto StartSend; goto StartSend;
@@ -533,7 +556,6 @@ namespace LFP_Manager.Threads
if (rPosition > 0) if (rPosition > 0)
{ {
OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1)); OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1));
Thread.Sleep(1); Thread.Sleep(1);
} }
else else
@@ -542,7 +564,6 @@ namespace LFP_Manager.Threads
if (TimeOutCount[ModuleID - 1] >= 10) if (TimeOutCount[ModuleID - 1] >= 10)
{ {
TimeOutCount[ModuleID - 1] = 10; TimeOutCount[ModuleID - 1] = 10;
//SystemData[0].CommFail = true;
if (SystemData[ModuleID - 1].ShelfCommFail == false) if (SystemData[ModuleID - 1].ShelfCommFail == false)
{ {
SystemData[ModuleID - 1].ShelfCommFail = true; SystemData[ModuleID - 1].ShelfCommFail = true;
@@ -562,6 +583,16 @@ namespace LFP_Manager.Threads
Thread.Sleep(100); Thread.Sleep(100);
} }
} }
catch (OperationCanceledException) { }
catch (Exception ex)
{
OnPrint?.Invoke(this, $"Comm thread error: {ex.Message}");
}
finally
{
SerialPortThreadEnd = true;
}
}
#endregion #endregion
} }