- 1.0.1.7 - 2025/12/17
* 124V RS-485 Thread Improved
This commit is contained in:
@@ -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,49 +79,73 @@ 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;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
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;
|
||||
|
||||
byte[] sRead = new byte[1024];
|
||||
int rLen = sPort.Read(sRead, 0, sRead.Length);
|
||||
|
||||
lock (_rxLock)
|
||||
{
|
||||
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,36 +155,75 @@ namespace LFP_Manager.Threads
|
||||
|
||||
private bool Open(string cPort, int cBaudrate)
|
||||
{
|
||||
sPort = new SerialPort();
|
||||
sPort.PortName = cPort;
|
||||
sPort.BaudRate = cBaudrate;
|
||||
lock (_portLock)
|
||||
{
|
||||
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.ErrorReceived += sErrorReceived;
|
||||
sPort.PinChanged += sPinChanged;
|
||||
|
||||
try
|
||||
{
|
||||
sPort.Open();
|
||||
return sPort.IsOpen;
|
||||
}
|
||||
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()
|
||||
{
|
||||
lock (_portLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnPrint?.Invoke(this, $"Port Close Fail: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -180,6 +234,7 @@ namespace LFP_Manager.Threads
|
||||
ModuleID = mID;
|
||||
UartPolling = flag;
|
||||
SystemData = aSystemData;
|
||||
if (SystemData != null && ModuleID - 1 >= 0 && ModuleID - 1 < SystemData.Length)
|
||||
SystemData[ModuleID - 1].mNo = ModuleID;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -254,6 +291,9 @@ namespace LFP_Manager.Threads
|
||||
private int rBufEnd = 0;
|
||||
|
||||
private void PutBuff(byte c)
|
||||
{
|
||||
// called from DataReceived event -> lock to be safe
|
||||
lock (_rxLock)
|
||||
{
|
||||
rBuffer[rBufStart++] = c;
|
||||
rBufStart %= BUFFER_SIZE;
|
||||
@@ -264,10 +304,13 @@ namespace LFP_Manager.Threads
|
||||
rBufEnd %= BUFFER_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int GetBuff()
|
||||
{
|
||||
int result = 0;
|
||||
lock (_rxLock)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
if (rBufStart != rBufEnd)
|
||||
{
|
||||
@@ -276,45 +319,20 @@ namespace LFP_Manager.Threads
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private void FlushBuff()
|
||||
{
|
||||
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,26 +437,39 @@ namespace LFP_Manager.Threads
|
||||
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;
|
||||
byte cData = 0;
|
||||
int[] TimeOutCount = new int[csConstData.SystemInfo.MAX_MODULE_SIZE];
|
||||
|
||||
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();
|
||||
byte[] txData = MakeTxDataDelta(false);
|
||||
if (sPort == null) return;
|
||||
if (txData != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
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}");
|
||||
}
|
||||
}
|
||||
|
||||
if (rFlag == true)
|
||||
{
|
||||
@@ -453,12 +477,13 @@ namespace LFP_Manager.Threads
|
||||
|
||||
RecvPacketInit();
|
||||
|
||||
while (true)
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
DateTime nDateTime = rDateTime.AddMilliseconds(RecvTimeout);
|
||||
if (nDateTime < DateTime.Now) break;
|
||||
|
||||
if (((getData = GetBuff()) & 0x0100) != 0x0000)
|
||||
getData = GetBuff();
|
||||
if ((getData & 0x0100) != 0x0000)
|
||||
{
|
||||
rDateTime = DateTime.Now;
|
||||
|
||||
@@ -466,7 +491,7 @@ namespace LFP_Manager.Threads
|
||||
|
||||
if (rPosition >= BUFFER_SIZE) RecvPacketInit();
|
||||
|
||||
if (BuffStart == false)
|
||||
if (!BuffStart)
|
||||
{
|
||||
if ((cData == (byte)ModuleID) || (cData == (byte)0x7F))
|
||||
{
|
||||
@@ -479,7 +504,8 @@ namespace LFP_Manager.Threads
|
||||
{
|
||||
ReadBuf[rPosition++] = cData;
|
||||
|
||||
switch (CsRs485CommFunction124050.ModbusPacketFromSlaveCheck(ReadBuf, rPosition))
|
||||
int chk = CsRs485CommFunction124050.ModbusPacketFromSlaveCheck(ReadBuf, rPosition);
|
||||
switch (chk)
|
||||
{
|
||||
case 0: // Need more data
|
||||
break;
|
||||
@@ -506,11 +532,8 @@ namespace LFP_Manager.Threads
|
||||
rFlag = false;
|
||||
if (OnDataRecv != null)
|
||||
{
|
||||
byte[] adata = new byte[rPosition + 1];
|
||||
for (int j = 0; j < adata.Length; j++)
|
||||
{
|
||||
adata[j] = ReadBuf[j];
|
||||
}
|
||||
var adata = new byte[rPosition];
|
||||
Array.Copy(ReadBuf, 0, adata, 0, rPosition);
|
||||
OnDataRecv(adata);
|
||||
}
|
||||
goto StartSend;
|
||||
@@ -533,7 +556,6 @@ namespace LFP_Manager.Threads
|
||||
if (rPosition > 0)
|
||||
{
|
||||
OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1));
|
||||
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
else
|
||||
@@ -542,7 +564,6 @@ namespace LFP_Manager.Threads
|
||||
if (TimeOutCount[ModuleID - 1] >= 10)
|
||||
{
|
||||
TimeOutCount[ModuleID - 1] = 10;
|
||||
//SystemData[0].CommFail = true;
|
||||
if (SystemData[ModuleID - 1].ShelfCommFail == false)
|
||||
{
|
||||
SystemData[ModuleID - 1].ShelfCommFail = true;
|
||||
@@ -562,6 +583,16 @@ namespace LFP_Manager.Threads
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnPrint?.Invoke(this, $"Comm thread error: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
SerialPortThreadEnd = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user