초기 커밋.

This commit is contained in:
2025-12-17 12:40:51 +09:00
parent e8d195c03e
commit 368acb1aa8
184 changed files with 95393 additions and 0 deletions

View File

@@ -0,0 +1,706 @@
using System;
using System.Threading;
using System.IO.Ports;
using System.Windows.Forms;
using LFP_Manager.DataStructure;
using LFP_Manager.Function;
using LFP_Manager.Utils;
namespace LFP_Manager.Threads
{
public sealed class CsRs232Thread124050 : IDisposable
{
#region ENUMS
private enum CommandType
{
NoCommand = 0,
WriteParam = 1,
WriteCoil = 2,
WriteRegister = 3,
ReadRegister = 4
}
private enum AddressChannel
{
Channel0 = 0,
Channel1 = 1,
Channel2 = 2,
Channel3 = 3
}
#endregion
#region CONSTANTS
private static class Constants
{
public const int BUFFER_SIZE = 512;
public const int DEFAULT_BAUD_RATE = 115200;
public const int MAX_TIMEOUT_COUNT = 5;
public const int DEFAULT_DATA_BITS = 8;
public const int POLLING_INTERVAL = 100;
public const int ERROR_RETRY_DELAY = 1000;
}
#endregion
#region PRIVATE FIELDS
private readonly object _lockObject = new object();
private readonly CommConfig _config;
private DeviceSystemData _systemData;
private readonly CancellationTokenSource _cancellationTokenSource;
private volatile bool _isRunning;
private volatile bool _isDisposed;
private SerialPort _serialPort;
private Thread _commThread;
private readonly byte[] _receiveBuffer;
private readonly byte[] _readBuffer;
private int _bufferStart;
private int _bufferEnd;
private ushort _readPosition;
private bool _bufferStarted;
private readonly TUartTxBuff _uartTxBuff;
private int _systemId;
private bool _uartPolling;
private bool _autoUartTx;
private AddressChannel _currentChannel;
private ushort _requestRegAddr;
private ushort _requestRegLen;
private bool _responseFlag;
private int _responseType;
private CommandType _currentCommand;
private int _timeoutCount;
private ushort _writeRegAddr;
private short _writeCoilRegData;
private byte[] _writeRegData;
#endregion
#region EVENTS
public event UartDataUpdate OnUpdate;
public event UartDataRecv OnDataRecv;
public event UartDataPrint OnPrint;
#endregion
#region CONSTRUCTORS
public CsRs232Thread124050(int systemId, CommConfig config, ref DeviceSystemData systemData)
{
if (config == null)
throw new ArgumentNullException(nameof(config));
_systemId = systemId;
_config = config;
_systemData = systemData;
_cancellationTokenSource = new CancellationTokenSource();
_receiveBuffer = new byte[Constants.BUFFER_SIZE];
_readBuffer = new byte[Constants.BUFFER_SIZE];
_uartTxBuff = new TUartTxBuff();
_autoUartTx = true;
InitializeSerialPort();
}
private void InitializeSerialPort()
{
try
{
_serialPort = new SerialPort();
_serialPort.BaudRate = Constants.DEFAULT_BAUD_RATE;
_serialPort.DataBits = Constants.DEFAULT_DATA_BITS;
_serialPort.StopBits = StopBits.One;
_serialPort.Parity = Parity.None;
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
_serialPort.DataReceived += SerialPort_DataReceived;
_serialPort.ErrorReceived += SerialPort_ErrorReceived;
_serialPort.PinChanged += SerialPort_PinChanged;
}
catch (Exception ex)
{
if (OnPrint != null)
{
OnPrint(this, string.Format("Failed to initialize serial port: {0}", ex.Message));
}
throw;
}
}
#endregion
#region PUBLIC METHODS
public bool Start(ref CommConfig config, int systemId, bool polling)
{
ThrowIfDisposed();
lock (_lockObject)
{
if (_isRunning)
return false;
_systemId = systemId;
_uartPolling = polling;
try
{
if (OpenPort(config.UartPort))
{
_isRunning = true;
_commThread = new Thread(CommThreadProcess);
_commThread.IsBackground = true;
_commThread.Name = "UART_Communication_Thread";
_commThread.Priority = ThreadPriority.AboveNormal;
_commThread.Start();
return true;
}
}
catch (Exception ex)
{
if (OnPrint != null)
{
OnPrint(this, string.Format("Failed to start UART thread: {0}", ex.Message));
}
}
return false;
}
}
public void Stop()
{
if (_isDisposed)
return;
lock (_lockObject)
{
_isRunning = false;
if (_cancellationTokenSource != null)
{
_cancellationTokenSource.Cancel();
}
ClosePort();
}
}
public void Dispose()
{
if (_isDisposed)
return;
Stop();
lock (_lockObject)
{
if (_cancellationTokenSource != null)
{
_cancellationTokenSource.Dispose();
}
if (_serialPort != null)
{
_serialPort.Dispose();
}
_isDisposed = true;
}
GC.SuppressFinalize(this);
}
public void SetPolling(bool flag, int systemId, ref DeviceSystemData systemData)
{
ThrowIfDisposed();
lock (_lockObject)
{
_systemId = systemId;
_uartPolling = flag;
_systemData = systemData;
_systemData.mNo = systemId;
}
}
public void SetAutoTx(bool autoTx)
{
ThrowIfDisposed();
lock (_lockObject)
{
_autoUartTx = autoTx;
}
}
public void SetWriteCoilReg(ushort writeAddr, short writeData)
{
ThrowIfDisposed();
lock (_lockObject)
{
_currentCommand = CommandType.WriteCoil;
_writeRegAddr = writeAddr;
_writeCoilRegData = writeData;
Thread.Sleep(500);
}
}
public void SetReadReg(ushort readAddr, ushort readLen, bool replyFlag)
{
ThrowIfDisposed();
lock (_lockObject)
{
_currentCommand = CommandType.ReadRegister;
_requestRegAddr = readAddr;
_requestRegLen = readLen;
_responseFlag = replyFlag;
}
}
public void SetWriteReg(ushort writeAddr, short[] writeData)
{
ThrowIfDisposed();
if (writeData == null)
throw new ArgumentNullException(nameof(writeData));
lock (_lockObject)
{
_currentCommand = CommandType.WriteParam;
_writeRegAddr = writeAddr;
TUartTRxData uartTRxData = new TUartTRxData();
uartTRxData.type = (int)CommandType.WriteParam;
uartTRxData.data = csSerialCommFunction.MakeWriteRegisterData((ushort)_systemId, writeAddr, writeData);
uartTRxData.length = uartTRxData.data.Length;
if (_uartTxBuff != null)
{
_uartTxBuff.PutBuff(uartTRxData);
}
}
}
#endregion
#region PRIVATE METHODS
private void ThrowIfDisposed()
{
if (_isDisposed)
throw new ObjectDisposedException(GetType().FullName);
}
private bool OpenPort(string portName)
{
try
{
if (string.IsNullOrEmpty(portName))
throw new ArgumentException("Port name cannot be null or empty", "portName");
if (_serialPort.IsOpen)
_serialPort.Close();
_serialPort.PortName = portName;
_serialPort.Open();
return true;
}
catch (Exception ex)
{
if (OnPrint != null)
{
OnPrint(this, string.Format("Failed to open port {0}: {1}", portName, ex.Message));
}
return false;
}
}
private void ClosePort()
{
try
{
if (_serialPort != null && _serialPort.IsOpen)
_serialPort.Close();
}
catch (Exception ex)
{
if (OnPrint != null)
{
OnPrint(this, string.Format("Error closing port: {0}", ex.Message));
}
}
}
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
if (!_serialPort.IsOpen) return;
int bytesToRead = _serialPort.BytesToRead;
if (bytesToRead == 0) return;
byte[] buffer = new byte[bytesToRead];
int bytesRead = _serialPort.Read(buffer, 0, bytesToRead);
lock (_lockObject)
{
for (int i = 0; i < bytesRead; i++)
{
AddToBuffer(buffer[i]);
}
}
}
catch (Exception ex)
{
if (OnPrint != null)
{
OnPrint(this, string.Format("Error in data receive: {0}", ex.Message));
}
}
}
private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
{
if (OnPrint != null)
{
OnPrint(this, string.Format("Serial port error: {0}", e.EventType));
}
}
private void SerialPort_PinChanged(object sender, SerialPinChangedEventArgs e)
{
if (OnPrint != null)
{
OnPrint(this, string.Format("Serial pin changed: {0}", e.EventType));
}
}
private void AddToBuffer(byte data)
{
_receiveBuffer[_bufferStart++] = data;
_bufferStart %= Constants.BUFFER_SIZE;
if (_bufferStart == _bufferEnd)
{
_bufferEnd = (_bufferEnd + 1) % Constants.BUFFER_SIZE;
}
}
private int GetFromBuffer()
{
if (_bufferStart == _bufferEnd)
return 0;
int result = 0x0100 + _receiveBuffer[_bufferEnd++];
_bufferEnd %= Constants.BUFFER_SIZE;
return result;
}
private void FlushBuffer()
{
_bufferStart = _bufferEnd = 0;
}
private void ProcessReceivedData()
{
if (_readPosition >= Constants.BUFFER_SIZE)
{
ResetReceiveState();
return;
}
if (!_bufferStarted)
{
int data = GetFromBuffer();
if ((data & 0xFF) == _systemId || (data & 0xFF) == 0x7F)
{
_readPosition = 0;
_readBuffer[_readPosition++] = (byte)(data & 0xFF);
_bufferStarted = true;
}
return;
}
int receivedByte = GetFromBuffer();
if ((receivedByte & 0x0100) == 0)
return;
_readBuffer[_readPosition++] = (byte)(receivedByte & 0xFF);
ProcessModbusResponse();
}
private void ProcessModbusResponse()
{
int result = csSerialCommFunction.ModbusPacketFromSlaveCheck(_readBuffer, _readPosition);
switch (result)
{
case 0: // Need more data
return;
case 1: // Valid packet
if (OnPrint != null)
{
OnPrint(this, csLog.trx_data_print(_readBuffer, _readPosition, 1));
}
_timeoutCount = 0;
ProcessValidResponse();
break;
case 2: // Firmware update packet
if (OnPrint != null)
{
OnPrint(this, csLog.trx_data_print(_readBuffer, _readPosition, 1));
}
_timeoutCount = 0;
ProcessFirmwareResponse();
break;
case -1: // Error packet
ResetReceiveState();
break;
}
}
private void ProcessValidResponse()
{
try
{
int moduleId = _readBuffer[0];
if (moduleId > 0) moduleId--;
_systemData.CommFail = false;
_systemData.ShelfCommFail = false;
if (_responseType == 0)
{
short[] resultCode = csSerialCommFunction124050.SerialRxProcess(_readBuffer, _requestRegAddr, _readPosition, ref _systemData);
if (OnUpdate != null)
{
OnUpdate(this, ref _systemData);
}
}
else
{
_responseType = 0;
if (OnDataRecv != null)
{
byte[] responseData = new byte[_readPosition];
Array.Copy(_readBuffer, responseData, _readPosition);
OnDataRecv(responseData);
}
}
}
catch (Exception ex)
{
if (OnPrint != null)
{
OnPrint(this, string.Format("Error processing valid response: {0}", ex.Message));
}
}
finally
{
ResetReceiveState();
}
}
private void ProcessFirmwareResponse()
{
try
{
if (OnDataRecv != null)
{
byte[] responseData = new byte[_readPosition];
Array.Copy(_readBuffer, responseData, _readPosition);
OnDataRecv(responseData);
}
}
catch (Exception ex)
{
if (OnPrint != null)
{
OnPrint(this, string.Format("Error processing firmware response: {0}", ex.Message));
}
}
finally
{
ResetReceiveState();
}
}
private void ResetReceiveState()
{
_bufferStarted = false;
_readPosition = 0;
_responseFlag = false;
}
private void CommThreadProcess()
{
while (_isRunning && !_cancellationTokenSource.Token.IsCancellationRequested)
{
try
{
ProcessCommunication();
Thread.Sleep(Constants.POLLING_INTERVAL);
}
catch (Exception ex)
{
if (OnPrint != null)
{
OnPrint(this, string.Format("Communication thread error: {0}", ex.Message));
}
Thread.Sleep(Constants.ERROR_RETRY_DELAY);
}
}
}
private void ProcessCommunication()
{
if (_serialPort == null || !_serialPort.IsOpen)
return;
bool writeMode = false;
byte[] txData = PrepareTransmitData(ref writeMode);
if (txData != null)
{
SendData(txData);
if (_responseFlag)
{
ProcessReceivedData();
}
}
}
private byte[] PrepareTransmitData(ref bool writeMode)
{
byte[] txData = null;
_responseType = 0;
if (_uartTxBuff != null && _uartTxBuff.CheckBuff())
{
TUartTRxData txBuffer = _uartTxBuff.GetBuff();
if (txBuffer != null)
{
txData = txBuffer.data;
writeMode = true;
_responseFlag = true;
_responseType = txBuffer.type;
}
}
else if (_currentCommand == CommandType.WriteCoil)
{
txData = csSerialCommFunction.MakeWriteCoilData((ushort)_systemId, _writeRegAddr, _writeCoilRegData);
_currentCommand = CommandType.NoCommand;
_responseFlag = true;
}
else if (_currentCommand == CommandType.ReadRegister)
{
txData = csSerialCommFunction.MakeReadRegisterData((ushort)_systemId, csSerialCommFunction.READ_HOLDING_REG, _requestRegAddr, _requestRegLen);
_currentCommand = CommandType.NoCommand;
_responseFlag = true;
}
else if (_uartPolling && _autoUartTx)
{
txData = PreparePollingData();
}
return txData;
}
private byte[] PreparePollingData()
{
ushort command;
switch (_currentChannel)
{
case AddressChannel.Channel0:
_currentChannel = AddressChannel.Channel1;
_requestRegAddr = 0x0000;
_requestRegLen = 0x0040;
command = csSerialCommFunction.READ_HOLDING_REG;
_responseFlag = true;
break;
case AddressChannel.Channel1:
_currentChannel = AddressChannel.Channel2;
_requestRegAddr = 0x0040;
_requestRegLen = 0x0040;
command = csSerialCommFunction.READ_HOLDING_REG;
_responseFlag = true;
break;
case AddressChannel.Channel2:
_currentChannel = AddressChannel.Channel3;
_requestRegAddr = 0x0080;
_requestRegLen = 0x0040;
command = csSerialCommFunction.READ_HOLDING_REG;
_responseFlag = true;
break;
case AddressChannel.Channel3:
if (_config.ModuleQty > 1)
{
_systemId++;
if (_systemId > _config.ModuleQty)
{
_systemId = 1;
}
}
_currentChannel = AddressChannel.Channel0;
command = csSerialCommFunction.NO_CMD;
_responseFlag = false;
break;
default:
_currentChannel = AddressChannel.Channel0;
_requestRegAddr = 0x0000;
_requestRegLen = 0x0040;
command = csSerialCommFunction.READ_HOLDING_REG;
break;
}
return command == csSerialCommFunction.NO_CMD ? null :
csSerialCommFunction.MakeReadRegisterData((ushort)_systemId, command, _requestRegAddr, _requestRegLen);
}
private void SendData(byte[] data)
{
try
{
if (data == null)
throw new ArgumentNullException("data");
FlushBuffer();
_serialPort.Write(data, 0, data.Length);
if (OnPrint != null)
{
OnPrint(this, csLog.trx_data_print(data, data.Length, 0));
}
}
catch (Exception ex)
{
if (OnPrint != null)
{
OnPrint(this, string.Format("Send data error: {0}", ex.Message));
}
throw;
}
}
#endregion
}
}