초기 커밋.

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,552 @@
using LFP_Manager.DataStructure;
using LFP_Manager.Function;
using LFP_Manager.Utils;
using Microsoft.Extensions.Logging;
using System;
using System.Data;
using System.Data.SQLite;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LFP_Manager.Threads
{
public class DbAsyncTask : IDisposable
{
#region FIELDS
private readonly CommConfig _config;
private DeviceSystemData[] _systemData;
private readonly short[] _status = new short[2];
private readonly short[] _oldStatus = new short[2];
private readonly int _moduleId;
private readonly int _moduleQuantity;
private readonly ILogger<DbAsyncTask> _logger;
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private Task _dbTask;
private readonly SemaphoreSlim _dataLock = new SemaphoreSlim(1, 1);
private readonly SemaphoreSlim _statusLock = new SemaphoreSlim(1, 1);
private volatile bool _isRunning;
private volatile bool _disposed;
// Connection pooling for better performance
private readonly object _connectionLock = new object();
private SQLiteConnection _connection;
public event DbDataPrint OnPrint;
#endregion
#region CONSTRUCTORS
public DbAsyncTask(int moduleId, CommConfig config, DeviceSystemData[] systemData, ILogger<DbAsyncTask> logger = null)
{
if (config == null)
throw new ArgumentNullException(nameof(config));
if (systemData == null)
throw new ArgumentNullException(nameof(systemData));
if (moduleId <= 0)
throw new ArgumentOutOfRangeException(nameof(moduleId), "Module ID must be positive");
_moduleId = moduleId;
_config = config;
_systemData = systemData;
_logger = logger ?? CreateDefaultLogger();
_moduleQuantity = CalculateModuleQuantity(_config.CommType, _config.ModuleQty);
_logger.LogInformation("DbAsyncTask initialized for Module {0} with {1} modules",
_moduleId, _moduleQuantity);
}
private static ILogger<DbAsyncTask> CreateDefaultLogger()
{
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole()
.AddDebug()
.SetMinimumLevel(LogLevel.Information);
});
return loggerFactory.CreateLogger<DbAsyncTask>();
}
#endregion
#region PUBLIC METHODS
public async Task<bool> StartAsync(CancellationToken cancellationToken)
{
if (_disposed)
throw new ObjectDisposedException(nameof(DbAsyncTask));
if (_isRunning)
{
_logger.LogWarning("DB thread for Module {0} is already running", _moduleId);
return true;
}
try
{
_logger.LogInformation("Starting DB thread for Module {0}", _moduleId);
await InitializeDatabaseAsync(cancellationToken).ConfigureAwait(false);
await InitializeConnectionAsync().ConfigureAwait(false);
_dbTask = DbThreadProcessAsync(_cancellationTokenSource.Token);
_isRunning = true;
_logger.LogInformation("DB thread started successfully for Module {0}", _moduleId);
OnPrint?.Invoke(this, string.Format("DB thread started for Module {0}", _moduleId));
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to start DB thread for Module {0}", _moduleId);
OnPrint?.Invoke(this, string.Format("Failed to start DB thread: {0}", ex.Message));
await CleanupResourcesAsync().ConfigureAwait(false);
return false;
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
if (_disposed || !_isRunning)
return;
_logger.LogInformation("Stopping DB thread for Module {0}", _moduleId);
_isRunning = false;
_cancellationTokenSource.Cancel();
if (_dbTask != null)
{
try
{
await _dbTask.ConfigureAwait(false);
_logger.LogInformation("DB thread stopped successfully for Module {0}", _moduleId);
}
catch (OperationCanceledException)
{
_logger.LogDebug("DB thread was cancelled for Module {0}", _moduleId);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error stopping DB thread for Module {0}", _moduleId);
OnPrint?.Invoke(this, string.Format("Error stopping DB thread: {0}", ex.Message));
}
}
await CleanupResourcesAsync().ConfigureAwait(false);
}
public async Task UpdateStatusAsync(short status1, short status2, CancellationToken cancellationToken)
{
await _statusLock.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
_status[0] = status1;
_status[1] = status2;
}
finally
{
_statusLock.Release();
}
_logger.LogTrace("Status updated for Module {ModuleId}: Status1={Status1}, Status2={Status2}",
_moduleId, status1, status2);
}
public async Task UpdateDataAsync(int moduleId, DeviceSystemData[] systemData, CancellationToken cancellationToken)
{
if (systemData == null)
throw new ArgumentNullException(nameof(systemData));
await _dataLock.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
_systemData = new DeviceSystemData[systemData.Length];
Array.Copy(systemData, _systemData, systemData.Length);
}
finally
{
_dataLock.Release();
}
_logger.LogDebug("System data updated for Module {ModuleId}", moduleId);
}
// Backward compatibility methods
public void UpdateStatus(short status1, short status2)
{
var task = UpdateStatusAsync(status1, status2, CancellationToken.None);
task.GetAwaiter().GetResult();
}
public void UpdateData(int moduleId, DeviceSystemData[] systemData)
{
var task = UpdateDataAsync(moduleId, systemData, CancellationToken.None);
task.GetAwaiter().GetResult();
}
#endregion
#region PRIVATE METHODS
private static int CalculateModuleQuantity(int commType, int configModuleQty)
{
if (commType == csConstData.CommType.COMM_RS485)
return Math.Max(1, configModuleQty);
return 1;
}
private async Task InitializeDatabaseAsync(CancellationToken cancellationToken)
{
string dbPath = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
if (string.IsNullOrEmpty(dbPath))
throw new InvalidOperationException("Unable to determine executable path");
await Task.Run(() => csHistoryFunction.DbCreate(dbPath), cancellationToken).ConfigureAwait(false);
}
private async Task InitializeConnectionAsync()
{
string dbFilename = System.IO.Path.GetDirectoryName(Application.ExecutablePath) + csDbConstData.DataBase.FileName;
string connectionString = string.Format("Data Source={0};Pooling=true;Max Pool Size=10;", dbFilename);
_connection = new SQLiteConnection(connectionString);
await _connection.OpenAsync().ConfigureAwait(false);
}
private async Task DbThreadProcessAsync(CancellationToken cancellationToken)
{
DateTime lastLogTime = DateTime.MinValue;
int logPeriodSeconds = Math.Max(1, _config.DbLogPeriod);
_logger.LogDebug("DB thread process started for Module {ModuleId}", _moduleId);
try
{
while (!cancellationToken.IsCancellationRequested && _isRunning)
{
try
{
DateTime currentTime = DateTime.Now;
if (ShouldLogData(lastLogTime, currentTime, logPeriodSeconds))
{
await ProcessDatabaseLoggingAsync(currentTime, cancellationToken).ConfigureAwait(false);
lastLogTime = currentTime;
}
// Check for alarms
await CheckAlarmAsync(cancellationToken).ConfigureAwait(false);
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
_logger.LogDebug("DB thread process cancelled for Module {ModuleId}", _moduleId);
break;
}
catch (Exception ex)
{
_logger.LogError(ex, "DB thread error for Module {ModuleId}", _moduleId);
OnPrint?.Invoke(this, string.Format("DB thread error: {0}", ex.Message));
// Exponential backoff for error recovery
int delay = Math.Min(10000, 1000 * (int)Math.Pow(2, Math.Min(5, 1)));
await Task.Delay(delay, cancellationToken).ConfigureAwait(false);
}
}
}
finally
{
_logger.LogDebug("DB thread process completed for Module {ModuleId}", _moduleId);
}
}
private static bool ShouldLogData(DateTime lastTime, DateTime currentTime, int periodSeconds)
{
if (lastTime == DateTime.MinValue)
return true;
TimeSpan timeDiff = currentTime - lastTime;
return timeDiff.TotalSeconds >= periodSeconds;
}
private async Task ProcessDatabaseLoggingAsync(DateTime currentTime, CancellationToken cancellationToken)
{
string modelName = csConstData.MODEL_STR[_config.UartModelIndex];
await Task.Run(() => csDbUtils.LogDbCreate(modelName), cancellationToken).ConfigureAwait(false);
DeviceSystemData[] systemDataCopy;
await _dataLock.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
systemDataCopy = new DeviceSystemData[_systemData.Length];
Array.Copy(_systemData, systemDataCopy, _systemData.Length);
}
finally
{
_dataLock.Release();
}
await LogDataByCommTypeAsync(modelName, systemDataCopy, currentTime, cancellationToken).ConfigureAwait(false);
}
private async Task LogDataByCommTypeAsync(string modelName, DeviceSystemData[] systemData, DateTime currentTime, CancellationToken cancellationToken)
{
switch (_config.CommType)
{
case csConstData.CommType.COMM_UART:
case csConstData.CommType.COMM_SNMP:
await LogSingleModuleAsync(modelName, systemData, currentTime, cancellationToken).ConfigureAwait(false);
break;
case csConstData.CommType.COMM_RS485:
await LogMultipleModulesAsync(modelName, systemData, currentTime, cancellationToken).ConfigureAwait(false);
break;
default:
_logger.LogWarning("Unknown communication type: {0}", _config.CommType);
break;
}
}
private async Task LogSingleModuleAsync(string modelName, DeviceSystemData[] systemData, DateTime currentTime, CancellationToken cancellationToken)
{
if (_moduleId > 0 && _moduleId <= systemData.Length)
{
systemData[_moduleId - 1].mNo = _moduleId;
await Task.Run(() => csDbUtils.BmsLogDataInsert(modelName, ref systemData[_moduleId - 1], currentTime, 1000), cancellationToken)
.ConfigureAwait(false);
}
}
private async Task LogMultipleModulesAsync(string modelName, DeviceSystemData[] systemData, DateTime currentTime, CancellationToken cancellationToken)
{
if (_moduleQuantity <= 1)
{
await LogSingleModuleAsync(modelName, systemData, currentTime, cancellationToken).ConfigureAwait(false);
return;
}
using (var semaphore = new SemaphoreSlim(Environment.ProcessorCount))
{
var tasks = new Task[Math.Min(_moduleQuantity, systemData.Length)];
for (int i = 0; i < tasks.Length; i++)
{
int moduleIndex = i;
tasks[i] = ProcessModuleAsync(semaphore, modelName, systemData, moduleIndex, currentTime, cancellationToken);
}
await Task.WhenAll(tasks).ConfigureAwait(false);
}
}
private async Task ProcessModuleAsync(SemaphoreSlim semaphore, string modelName, DeviceSystemData[] systemData, int index, DateTime currentTime, CancellationToken cancellationToken)
{
await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
systemData[index].mNo = index + 1;
await Task.Run(() => csDbUtils.BmsLogDataInsert(modelName, ref systemData[index], currentTime, 1000), cancellationToken)
.ConfigureAwait(false);
}
finally
{
semaphore.Release();
}
}
private async Task CheckAlarmAsync(CancellationToken cancellationToken)
{
short[] currentStatus = new short[2];
short[] previousStatus = new short[2];
await _statusLock.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
Array.Copy(_status, currentStatus, 2);
Array.Copy(_oldStatus, previousStatus, 2);
}
finally
{
_statusLock.Release();
}
if (HasStatusChanged(currentStatus, previousStatus))
{
await ProcessAlarmChangesAsync(currentStatus, previousStatus, cancellationToken).ConfigureAwait(false);
await _statusLock.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
Array.Copy(_status, _oldStatus, 2);
}
finally
{
_statusLock.Release();
}
}
}
private static bool HasStatusChanged(short[] current, short[] previous)
{
return current[0] != previous[0] || current[1] != previous[1];
}
private async Task ProcessAlarmChangesAsync(short[] currentStatus, short[] previousStatus, CancellationToken cancellationToken)
{
bool[] currentBits1 = csUtils.Int16ToBitArray(currentStatus[0]);
bool[] currentBits2 = csUtils.Int16ToBitArray(currentStatus[1]);
bool[] previousBits1 = csUtils.Int16ToBitArray(previousStatus[0]);
bool[] previousBits2 = csUtils.Int16ToBitArray(previousStatus[1]);
_logger.LogTrace("Processing alarm changes for Module {ModuleId}", _moduleId);
await CheckCellVoltageAlarmAsync(currentBits1, currentBits2, previousBits1, previousBits2, cancellationToken).ConfigureAwait(false);
}
private async Task CheckCellVoltageAlarmAsync(bool[] currentBits1, bool[] currentBits2, bool[] previousBits1, bool[] previousBits2, CancellationToken cancellationToken)
{
// Cell Over/Under Voltage Check
if (previousBits2[0] != currentBits2[0])
{
if (currentBits2[0])
{
await InsertAlarmRecordAsync(csDbConstData.DB_ALARM.CELL_UNDER_VOLTAGE, csDbConstData.DB_ALARM.FLAG_TRIP, cancellationToken).ConfigureAwait(false);
}
else
{
await HandleVoltageWarningOrReleaseAsync(currentBits1, previousBits1, cancellationToken).ConfigureAwait(false);
}
}
else if (previousBits1[0] != currentBits1[0])
{
await HandleVoltageWarningOrReleaseAsync(currentBits1, previousBits1, cancellationToken).ConfigureAwait(false);
}
}
private async Task HandleVoltageWarningOrReleaseAsync(bool[] currentBits1, bool[] previousBits1, CancellationToken cancellationToken)
{
int flag = currentBits1[0] ?
csDbConstData.DB_ALARM.FLAG_WARNING :
csDbConstData.DB_ALARM.FLAG_RELEASE;
await InsertAlarmRecordAsync(csDbConstData.DB_ALARM.CELL_UNDER_VOLTAGE, flag, cancellationToken).ConfigureAwait(false);
}
private async Task InsertAlarmRecordAsync(int alarmCode, int flagCode, CancellationToken cancellationToken)
{
if (_connection == null || _connection.State != ConnectionState.Open)
{
await InitializeConnectionAsync().ConfigureAwait(false);
}
using (var transaction = _connection.BeginTransaction())
{
try
{
using (var command = _connection.CreateCommand())
{
command.Transaction = transaction;
command.CommandText = string.Format(
"INSERT INTO {0} (HTime, model, sno, alarm_name, alarm_code, flag_name, flag, param1, param2) " +
"VALUES (@HTime, @model, @sno, @alarm_name, @alarm_code, @flag_name, @flag, @param1, @param2)",
csDbConstData.DataBase.TableName);
AddParameters(command, alarmCode, flagCode);
await Task.Run(() => command.ExecuteNonQuery(), cancellationToken).ConfigureAwait(false);
}
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
private static void AddParameters(SQLiteCommand command, int alarmCode, int flagCode)
{
var parameters = new[]
{
new SQLiteParameter("@HTime", DbType.DateTime) { Value = DateTime.Now },
new SQLiteParameter("@model", DbType.String) { Value = "AAA" },
new SQLiteParameter("@sno", DbType.Int16) { Value = 1 },
new SQLiteParameter("@alarm_name", DbType.String) { Value = csDbConstData.DB_ALARM.ALARM_NAME[alarmCode] },
new SQLiteParameter("@alarm_code", DbType.Int16) { Value = alarmCode },
new SQLiteParameter("@flag_name", DbType.String) { Value = csDbConstData.DB_ALARM.FLAG_NAME[flagCode] },
new SQLiteParameter("@flag", DbType.Int16) { Value = flagCode },
new SQLiteParameter("@param1", DbType.Decimal) { Value = 0.0m },
new SQLiteParameter("@param2", DbType.Decimal) { Value = 0.0m }
};
command.Parameters.AddRange(parameters);
}
private async Task CleanupResourcesAsync()
{
if (_connection != null)
{
try
{
if (_connection.State == ConnectionState.Open)
{
_connection.Close();
}
_connection.Dispose();
_connection = null;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error cleaning up database connection for Module {0}", _moduleId);
}
}
await Task.CompletedTask.ConfigureAwait(false);
}
#endregion
#region DISPOSE PATTERN
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed && disposing)
{
try
{
StopAsync(CancellationToken.None).GetAwaiter().GetResult();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error during disposal for Module {0}", _moduleId);
}
_cancellationTokenSource?.Dispose();
_dataLock?.Dispose();
_statusLock?.Dispose();
_connection?.Dispose();
_disposed = true;
}
}
#endregion
}
}

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
}
}

View File

@@ -0,0 +1,568 @@
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;
using DevExpress.XtraGauges.Core.Model;
namespace LFP_Manager.Threads
{
class CsRs485Thread124050
{
#region VARIABLES
private readonly CommConfig Config;
private DeviceSystemData[] SystemData;
private Thread serialComm = null;
private SerialPort sPort = null;
private bool SerialPortThreadEnd = true;
public int ModuleID = 1;
private bool UartPolling = false;
private bool AutoUartTx = true;
private int addr_ch = 0;
private ushort RequestRegAddr = 0x0000; //Byul Init 0x0000
private ushort RequestRegLen = 50;
private bool rFlag = false;
private int wFlag = 0;
private int rFlag2 = 0;
private ushort ExtReqRegAddr = 0x0000;
private ushort WriteRegAddr = 0x0000; //Byul Init 0x0000
private short WriteCoilRegData = 0;
private byte[] WriteRegData;
private short WriteParamRegData;
private TUartTxBuff UartTxBuff;
public event UartDataUpdateRS485 OnUpdate = null;
public event UartDataRecvRS485 OnDataRecv = null;
public event UartDataPrintRS485 OnPrint = null;
#endregion
#region CONSTRUCTORS
public CsRs485Thread124050(int mID, CommConfig aConfig, ref DeviceSystemData[] aSystemData)
{
ModuleID = mID;
Config = aConfig;
SystemData = aSystemData;
UartTxBuff = new TUartTxBuff();
serialComm = new Thread(uartCommThread);
}
public void disposeThread()
{
if (sPort != null)
{
if (sPort.IsOpen)
{
sPort.Close();
}
sPort = null;
}
SerialPortThreadEnd = true;
if (serialComm != null)
{
if (serialComm.IsAlive)
{
serialComm.Abort();
}
serialComm = null;
}
}
public bool Start(ref CommConfig aConfig, int mID, bool aPolling)
{
bool result = false;
ModuleID = mID;
UartPolling = aPolling;
if (Open(aConfig.UartPort, 9600)) //Byul Init 9600
{
SerialPortThreadEnd = false;
serialComm.Start();
result = true;
}
return result;
}
public void Stop()
{
SerialPortThreadEnd = true;
Close();
}
#endregion
#region COMMPORT CONTROLS
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);
for (int i = 0; i < rLen; i++)
{
PutBuff(sRead[i]);
}
}
catch (Exception)
{
}
}
private void sErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
{
//
//csMakeDataFunction.SetData()
}
private void sPinChanged(object sender, System.IO.Ports.SerialPinChangedEventArgs e)
{
//
}
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
{
sPort.Open();
}
catch (Exception ex)
{
throw new Exception("Error Open - " + ex.Message);
}
return sPort.IsOpen;
}
private void Close()
{
if (sPort != null)
{
if (sPort.IsOpen)
{
sPort.Close();
}
sPort = null;
}
}
#endregion
#region PUBLIC FUNCTION
public void SetPolling(bool flag, int mID, ref DeviceSystemData[] aSystemData)
{
ModuleID = mID;
UartPolling = flag;
SystemData = aSystemData;
SystemData[ModuleID - 1].mNo = ModuleID;
}
public void SetAutoTx(bool 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)
{
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;
UartTxBuff?.PutBuff(uartTRxData);
}
public void SetParam(ushort WriteAddr, short WriteData)
{
byte[] sData = CsRs485CommFunction124050.MakeWriteRegisterData((ushort)ModuleID, WriteAddr, WriteData);
if (sData != null)
{
TUartTRxData aData = new TUartTRxData();
aData.length = sData.Length;
aData.data = sData;
UartTxBuff.PutBuff(aData);
}
}
public void SetReadWriteParam(ushort WriteAddr, short WriteData)
{
byte[] sData = CsRs485CommFunction124050.MakeReadWriteRegisterData((ushort)ModuleID, WriteAddr, WriteData);
if (sData != null)
{
TUartTRxData aData = new TUartTRxData();
aData.length = sData.Length;
aData.data = sData;
ExtReqRegAddr = WriteAddr;
UartTxBuff.PutBuff(aData);
}
}
#endregion
#region RX BUFFERING
private const int BUFFER_SIZE = 512;
private readonly byte[] rBuffer = new byte[BUFFER_SIZE];
private int rBufStart = 0;
private int rBufEnd = 0;
private void PutBuff(byte c)
{
rBuffer[rBufStart++] = c;
rBufStart %= BUFFER_SIZE;
if (rBufStart == rBufEnd)
{
rBufEnd++;
rBufEnd %= BUFFER_SIZE;
}
}
private int GetBuff()
{
int result = 0;
if (rBufStart != rBufEnd)
{
result = 0x0100 + rBuffer[rBufEnd++];
rBufEnd %= BUFFER_SIZE;
}
return result;
}
private void FlushBuff()
{
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;
if ((UartTxBuff != null) && (UartTxBuff.CheckBuff()))
{
TUartTRxData sBuff = UartTxBuff.GetBuff();
if (sBuff != null)
{
sData = sBuff.data;
wData = true;
rFlag = true;
rFlag2 = sBuff.type;
RequestRegAddr = ExtReqRegAddr;
}
}
else
{
if (AutoUartTx && UartPolling)
{
ushort sCmd;
switch (addr_ch)
{
case 0: // Battery Status Data
addr_ch = 1;
RequestRegAddr = 0x0FFF; //Byul Init 0x0000
RequestRegLen = 0x4C;
sCmd = CsSerialCommFunctionDelta.READ_INPUT_REG; // Command 0x04
rFlag = true;
break;
case 1: // Gyroscope Data
addr_ch = 2;
RequestRegAddr = 0x4000;
RequestRegLen = 7;
sCmd = CsSerialCommFunctionDelta.READ_INPUT_REG; // Command 0x17
rFlag = true;
break;
case 2:
addr_ch = 3;
RequestRegAddr = 0x3000;
RequestRegLen = 3;
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;
RequestRegLen = 28;
sCmd = CsSerialCommFunctionDelta.READ_HOLDING_REG; // Command 0x03
rFlag = true;
break;
case 4:
if (Config.ModuleQty > 1)
{
ModuleID++;
if (ModuleID > Config.ModuleQty)
{
ModuleID = 1;
}
}
addr_ch = 0;
sCmd = CsSerialCommFunctionDelta.NO_CMD;
rFlag = false;
break;
default:
addr_ch = 0;
RequestRegAddr = 0x0FFF; //Byul Init 0x0000
RequestRegLen = 27;
sCmd = CsSerialCommFunctionDelta.READ_INPUT_REG; // Command 0x04
rFlag = true;
break;
}
if (sCmd == CsSerialCommFunctionDelta.NO_CMD)
{
sData = null;
}
else if (sCmd == CsSerialCommFunctionDelta.READ_DEV_ID)
{
sData = CsSerialCommFunctionDelta.MakeReadDevIdRegReqData((ushort)ModuleID, sCmd, RequestRegAddr);
}
else
{
sData = CsSerialCommFunctionDelta.MakeReadRegisterData((ushort)ModuleID, sCmd, RequestRegAddr, RequestRegLen);
}
}
}
return sData;
}
#endregion
#region COMM THREAD
private readonly byte[] ReadBuf = new byte[BUFFER_SIZE];
ushort rPosition = 0;
bool BuffStart = false;
private void RecvPacketInit()
{
BuffStart = false;
rPosition = 0;
}
private void uartCommThread()
{
int RecvTimeout = Config.RecvWaitTime;
int getData = 0;
byte cData = 0;
int[] TimeOutCount = new int[csConstData.SystemInfo.MAX_MODULE_SIZE];
StartSend:
while (SerialPortThreadEnd == false)
{
if ((sPort == null) || (sPort.IsOpen == false)) continue;
FlushBuff();
byte[] txData = MakeTxDataDelta(false);
if (sPort == null) return;
if (txData != null)
{
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)
{
DateTime nDateTime = rDateTime.AddMilliseconds(RecvTimeout);
if (nDateTime < DateTime.Now) break;
if (((getData = GetBuff()) & 0x0100) != 0x0000)
{
rDateTime = DateTime.Now;
cData = (byte)(getData & 0x00FF);
if (rPosition >= BUFFER_SIZE) RecvPacketInit();
if (BuffStart == false)
{
if ((cData == (byte)ModuleID) || (cData == (byte)0x7F))
{
rPosition = 0;
ReadBuf[rPosition++] = cData;
BuffStart = true;
}
}
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);
}
else
{
Thread.Sleep(1);
}
}
if (rPosition > 0)
{
OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1));
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);
}
else
{
Thread.Sleep(10);
} /* if (rFlag == true) */
rPosition = 0;
Thread.Sleep(100);
}
}
#endregion
}
}

View File

@@ -0,0 +1,526 @@
using LFP_Manager.DataStructure;
using LFP_Manager.Function;
using SnmpSharpNet;
using System;
using System.Net;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using LFP_Manager.Utils;
using System.Windows.Forms;
using static DevExpress.Xpo.Helpers.AssociatedCollectionCriteriaHelper;
namespace LFP_Manager.Threads
{
public delegate void SetResult(string result, bool error);
public delegate void DataUpdate(object sender, ref DeviceSystemData rData);
class CsSnmpThread
{
#region VARIABLES
private DeviceSystemData SystemData;
private CommConfig Config;
private Thread snmpThread = null;
private bool snmpThreadHold = true;
private string targetIP = "";
private bool snmpDataRecv = false;
private string snmpResult = "";
private bool AutoSnmpTx = true;
private int type = 0;
private int OidIndex = 0;
private int OidMax = 0;
private int OidIndexBase = 0;
private int CommTimeOut = 0;
private string[] OidList;
private int SetSnmpMode = 0;
private int SetSnmpMode1 = 0;
private UInt32 SetSnmpValue = 0;
private string SetSnmpStringData;
public event DataUpdate OnUpdate = null;
public event SetResult OnSetResult = null;
#endregion
#region CONSTRUCTORS
public CsSnmpThread()
{
snmpThread = new Thread(snmpThreadFuncA);
snmpThread.Start();
}
public CsSnmpThread(CommConfig aConfig, ref DeviceSystemData aSystemData)
{
Config = aConfig;
type = Config.SnmpModelIndex;
OidIndex = 0;
OidList = CsSnmpConstData.SnmpOidInfo;
OidMax = OidList.Length;
SystemData = aSystemData;
snmpThread = new Thread(snmpThreadFuncA);
snmpThread.Start();
}
#endregion
#region PUBLIC FUNCTION
public void disposeThread()
{
snmpThreadHold = true;
snmpThread.Abort();
}
public void Start(string IP, bool autoTx)
{
targetIP = IP;
snmpThreadHold = false;
AutoSnmpTx = autoTx;
}
public void Stop()
{
snmpThreadHold = true;
}
public bool GetStatus()
{
return snmpThreadHold;
}
public string GetResult()
{
string result = "";
if (snmpDataRecv)
{
result = snmpResult;
snmpDataRecv = false;
}
return result;
}
public void SetAutoTx(bool autoTx)
{
AutoSnmpTx = autoTx;
}
#endregion
#region COMM. THREAD
public string GetSnmpOidInfo(int index)
{
return OidList[index];
}
bool SetCmdbySnmp(UdpTarget sTarget, int mode, UInt32 value, string svalue)
{
bool resultError = false;
Pdu SetPdu = new Pdu(PduType.Set);
// Set a value to unsigned integer
SetPdu.VbList.Clear();
switch (mode)
{
case 1: // Reset Command
SetPdu.VbList.Add(new Oid(".1.3.6.1.4.1.33.13.1.0"), new Integer32(Convert.ToInt32(value)));
break;
case 2: // Module Quantity Set
SetPdu.VbList.Add(new Oid(".1.3.6.1.4.1.33.2.4.0"), new Integer32(Convert.ToInt32(value)));
break;
case 3: // Alarm Output Mode
SetPdu.VbList.Add(new Oid(".1.3.6.1.4.1.33.2.5.0"), new Integer32(Convert.ToInt32(value)));
break;
case 4: // Manufacture Date
SetPdu.VbList.Add(new Oid(".1.3.6.1.4.1.33.2.6.0"), new Integer32(Convert.ToInt32(value)));
break;
case 5: // BMS Serial Number
SetPdu.VbList.Add(new Oid(".1.3.6.1.4.1.33.2.7.0"), new OctetString(svalue));
break;
}
// Set Agent security parameters
AgentParameters aparam = new AgentParameters(SnmpVersion.Ver1, new OctetString("public"));
// Make SNMP request
try
{
// Send request and wait for response
SnmpV1Packet result = sTarget.Request(SetPdu, aparam) as SnmpV1Packet;
// If result is null then agent didn't reply or we couldn't parse the reply.
if (result != null)
{
// ErrorStatus other then 0 is an error returned by
// the Agent - see SnmpConstants for error definitions
if (result.Pdu.ErrorStatus != 0)
{
// agent reported an error with the request
snmpResult = String.Format("Error in SNMP reply. Error {0} index {1}",
result.Pdu.ErrorStatus,
result.Pdu.ErrorIndex);
if (OnSetResult != null)
{
OnSetResult(snmpResult, true);
}
}
else
{
// Everything is ok. Agent will return the new value for the OID we changed
string resultString;
if (result.Pdu.VbList[0].Type == AsnType.OCTETSTRING)
resultString = result.Pdu.VbList[0].Value.ToString();
else
resultString = result.Pdu.VbList[0].Value.ToString();
snmpResult = String.Format("SNMP Received data. result {0}",
resultString);
OnSetResult?.Invoke(snmpResult, false);
}
}
else
{
if (snmpDataRecv == false)
{
snmpResult = DateTime.Now.ToString("[yyyy-MM-dd hh:mm:ss] ") + String.Format("No response received from SNMP agent.");
snmpDataRecv = true;
OnSetResult?.Invoke(snmpResult, true);
}
}
}
catch (Exception ex)
{
if (snmpDataRecv == false)
{
snmpResult = "[" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "] " + String.Format("Exception : {0}", ex.Message);
snmpDataRecv = true;
OnSetResult?.Invoke(snmpResult, true);
}
resultError = true;
}
return resultError;
}
public void SetDataBySnmp(int mode, UInt32 value)
{
SetSnmpMode = mode;
SetSnmpValue = value;
}
public void SetDataBySnmp(int mode, string value)
{
SetSnmpMode1 = mode;
SetSnmpStringData = value;
}
private void snmpThreadFuncA()
{
while (true)
{
if (snmpThreadHold == false)
{
// SNMP community name
OctetString community = new OctetString("admin");
// Define agent parameters class
AgentParameters param = new AgentParameters(community);
// Set SNMP version to 1 (or 2)
param.Version = SnmpVersion.Ver1;
// Construct the agent address object
// IpAddress class is easy to use here because
// it will try to resolve constructor parameter if it doesn't
// parse to an IP address
String dstAddr = targetIP;
IpAddress agent = new IpAddress(dstAddr);
// Construct target
UdpTarget target = new UdpTarget((IPAddress)agent, 161, 1000, 1);
// Pdu class used for all requests
Pdu pdu = new Pdu(PduType.Get);
if (SetSnmpMode != 0)
{
SetCmdbySnmp(target, SetSnmpMode, SetSnmpValue, SetSnmpStringData);
SetSnmpMode = 0;
}
else if (SetSnmpMode1 != 0)
{
SetCmdbySnmp(target, SetSnmpMode1, SetSnmpValue, SetSnmpStringData);
SetSnmpMode1 = 0;
}
else
{
// SNMP GET
while (AutoSnmpTx)
{
snmpResult = "";
if ((SetSnmpMode != 0) || (SetSnmpMode1 != 0))
{
break;
}
pdu.VbList.Clear();
pdu.VbList.Add(GetSnmpOidInfo(OidIndex));
// Make SNMP request
try
{
//SnmpV1Packet result = (SnmpV1Packet)target.Request(pdu, param);
target.Timeout = 100;
// agent reported an error with the request
snmpResult = csLog.trx_msg_print(string.Format("SEND {0}: OID [{1}]"
, target.Address.ToString()
, pdu.VbList[0].Oid.ToString()
)
, 0
)
;
OnSetResult?.Invoke(snmpResult, true);
SnmpV1Packet result = (SnmpV1Packet)target.Request(pdu, param);
// If result is null then agent didn't reply or we couldn't parse the reply.
if (result != null)
{
// ErrorStatus other then 0 is an error returned by
// the Agent - see SnmpConstants for error definitions
if (result.Pdu.ErrorStatus != 0)
{
// agent reported an error with the request
snmpResult = csLog.trx_msg_print(string.Format("Error in SNMP reply. Error {0} index {1} - {2}"
, result.Pdu.ErrorStatus
, result.Pdu.ErrorIndex
, result.Pdu.VbList[0].Oid.ToString()
)
, 1
)
;
OnSetResult?.Invoke(snmpResult, true);
}
else
{
snmpResult = csLog.trx_msg_print(string.Format("RECV {0}: OID [{1}]: [{2}]"
, target.Address.ToString()
, result.Pdu.VbList[0].Oid.ToString()
, result.Pdu.VbList[0].Value.ToString()
)
, 1
)
;
OnSetResult?.Invoke(snmpResult, true);
String resultTxt = "";
// Reply variables are returned in the same order as they were added
// to the VbList
//resultTxt = String.Format("[{0}] ({1}): {2}",
// result.Pdu.VbList[0].Oid.ToString(),
// SnmpConstants.GetTypeName(result.Pdu.VbList[0].Value.Type),
// result.Pdu.VbList[0].Value.ToString());
resultTxt = String.Format(".{0}", result.Pdu.VbList[0].Oid.ToString());
uint[] resultInt = (uint[])result.Pdu.VbList[0].Oid;
int len = resultInt.Length;
if ((resultInt[0] == 1)
&& (resultInt[1] == 3)
&& (resultInt[2] == 6)
&& (resultInt[3] == 1)
&& (resultInt[4] == 2)
&& (resultInt[5] == 1)
&& (resultInt[6] == 15)
)
{
//double resultDouble = 0.0;
if (result.Pdu.VbList[0].Value.Type == AsnType.OCTETSTRING)
{
try
{
//resultDouble = Convert.ToDouble(result.Pdu.VbList[0].Value.ToString());
csMakeDataFunction.SetSnmpData((int)resultInt[7], result.Pdu.VbList[0].Value.ToString(), ref SystemData);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
else if (result.Pdu.VbList[0].Type == AsnType.OCTETSTRING)
{
MessageBox.Show(result.Pdu.VbList[0].Value.ToString());
}
CalcAvgTemperatureModule(ref SystemData, (uint)SystemData.tempQty);
CheckShelfCommFail(ref SystemData);
OnUpdate?.Invoke(this, ref SystemData);
}
CommTimeOut = 0;
SystemData.CommFail = false;
}
Thread.Sleep(50);
}
else
{
if (snmpDataRecv == false)
{
snmpResult = DateTime.Now.ToString("[yyyy-MM-dd hh:mm:ss] ") + String.Format("No response received from SNMP agent.");
snmpDataRecv = true;
}
CommTimeOut++;
if (CommTimeOut >= 20)
{
SystemData.CommFail = true;
InitModuleData();
CommTimeOut = 20;
}
}
OidIndex++;
OidIndex %= OidMax;
Thread.Sleep(1);
}
catch (Exception ex)
{
snmpResult = csLog.trx_msg_print(string.Format("Exception in SNMP reply. Error {0} - {1}"
, pdu.VbList[0].Oid.ToString()
, ex.Message
)
, 1
)
;
OnSetResult?.Invoke(snmpResult, true);
CommTimeOut++;
if (CommTimeOut >= 10)
{
SystemData.CommFail = true;
InitModuleData();
CommTimeOut = 10;
}
break;
}
}
CheckShelfCommFail(ref SystemData);
OnUpdate?.Invoke(this, ref SystemData);
}
pdu.Clone();
target.Close();
Thread.Sleep(500);
}
}
}
private void InitModuleData()
{
SystemData.ValueData.voltageOfPack = 0;
SystemData.ValueData.current = 0;
SystemData.ValueData.averageCurrent = 0;
SystemData.ValueData.rSOC = 0;
SystemData.ValueData.stateOfHealth = 0;
for (int i = 0; i < SystemData.ValueData.CellVoltage.Length; i++)
{
SystemData.ValueData.CellVoltage[i] = 0;
}
for (int i = 0; i < SystemData.ValueData.CellTemperature.Length; i++)
{
SystemData.ValueData.CellTemperature[i] = 0;
}
SystemData.AvgData.avgCellVoltage = 0;
SystemData.AvgData.diffCellVoltage = 0;
SystemData.AvgData.maxCellVoltage = 0;
SystemData.AvgData.minCellVoltage = 0;
SystemData.AvgData.maxCellNum = 0;
SystemData.AvgData.minCellNum = 0;
SystemData.AvgData.avgTemp = 0;
SystemData.AvgData.diffTemp = 0;
SystemData.AvgData.maxTemp = 0;
SystemData.AvgData.minTemp = 0;
SystemData.AvgData.maxTempNum = 0;
SystemData.AvgData.minTempNum = 0;
}
private void CheckShelfCommFail(ref DeviceSystemData aSystemData)
{
if (aSystemData.StatusData.batteryStatus == 0x0003)
{ aSystemData.ShelfCommFail = true; }
else
{ aSystemData.ShelfCommFail = false; }
}
#endregion
static void CalcAvgTemperatureModule(ref DeviceSystemData aSystemData, UInt32 tSize)
{
short i, j;
int sum;
TMinMax min, max;
min = new TMinMax();
max = new TMinMax();
sum = 0;
max.value = 0;
max.num = 0;
min.value = 0;
min.num = 0;
j = 0;
for (i = 0; i < tSize; i++)
{
if (j == 0)
{
max.value = aSystemData.ValueData.CellTemperature[i];
max.num = i;
min.value = aSystemData.ValueData.CellTemperature[i];
min.num = i;
}
if (max.value < aSystemData.ValueData.CellTemperature[i])
{
max.value = aSystemData.ValueData.CellTemperature[i];
max.num = i;
}
if (min.value > aSystemData.ValueData.CellTemperature[i])
{
min.value = aSystemData.ValueData.CellTemperature[i];
min.num = i;
}
sum += aSystemData.ValueData.CellTemperature[i];
j++;
}
if (j == 0)
{ aSystemData.AvgData.avgTemp = 0; }
else
{ aSystemData.AvgData.avgTemp = (short)(sum / j); }
aSystemData.AvgData.maxTemp = max.value;
aSystemData.AvgData.maxTempNum = max.num;
aSystemData.AvgData.minTemp = min.value;
aSystemData.AvgData.minTempNum = min.num;
}
}
}

View File

@@ -0,0 +1,583 @@
using LFP_Manager.DataStructure;
using LFP_Manager.Function;
using LFP_Manager.Utils;
using SnmpSharpNet;
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace LFP_Manager.Threads
{
/// <summary>
/// 향상된 SNMP 통신 스레드 클래스 - 안전하고 효율적인 리소스 관리
/// </summary>
public class CsSnmpThread124050 : IDisposable
{
#region CONSTANTS
private const int MAX_COMM_TIMEOUT = 20;
private const int SNMP_TIMEOUT_MS = 1000;
private const int SNMP_RETRIES = 1;
private const int SNMP_PORT = 161;
private const int THREAD_SLEEP_MS = 50;
private const int OPERATION_SLEEP_MS = 500;
private const string DEFAULT_COMMUNITY = "admin";
#endregion
#region FIELDS
private DeviceSystemData _systemData;
private readonly CommConfig _config;
private readonly string[] _oidList;
private readonly object _lockObject = new object();
private Task _snmpTask;
private CancellationTokenSource _cancellationTokenSource;
private volatile bool _disposed = false;
private string _targetIP = "";
private bool _autoSnmpTx = true;
private int _oidIndex = 0;
private int _commTimeOut = 0;
// SNMP SET 관련 필드
private volatile int _setSnmpMode = 0;
private volatile int _setSnmpMode1 = 0;
private volatile uint _setSnmpValue = 0;
private volatile string _setSnmpStringData = "";
// 이벤트 및 델리게이트
public event DataUpdate OnUpdate;
public event SetResult OnSetResult;
#endregion
#region CONSTRUCTORS
public CsSnmpThread124050()
{
_cancellationTokenSource = new CancellationTokenSource();
_snmpTask = Task.Run(() => SnmpThreadFunction(_cancellationTokenSource.Token));
}
public CsSnmpThread124050(CommConfig config, ref DeviceSystemData systemData)
{
_config = config ?? throw new ArgumentNullException(nameof(config));
_systemData = systemData ?? throw new ArgumentNullException(nameof(systemData));
_oidList = CsSnmpConstData124050.SnmpOidInfo;
if (_oidList == null || _oidList.Length == 0)
{
throw new InvalidOperationException("OID 목록이 비어있습니다.");
}
_cancellationTokenSource = new CancellationTokenSource();
_snmpTask = Task.Run(() => SnmpThreadFunction(_cancellationTokenSource.Token));
}
#endregion
#region PUBLIC METHODS
/// <summary>
/// SNMP 통신 시작
/// </summary>
public void Start(string ip, bool autoTx = true)
{
if (string.IsNullOrWhiteSpace(ip))
throw new ArgumentException("IP 주소가 유효하지 않습니다.", nameof(ip));
lock (_lockObject)
{
_targetIP = ip;
_autoSnmpTx = autoTx;
}
}
/// <summary>
/// SNMP 통신 중지
/// </summary>
public void Stop()
{
lock (_lockObject)
{
_autoSnmpTx = false;
}
}
/// <summary>
/// 현재 상태 반환
/// </summary>
public bool IsRunning => _autoSnmpTx && !_disposed;
/// <summary>
/// 자동 전송 모드 설정
/// </summary>
public void SetAutoTx(bool autoTx)
{
lock (_lockObject)
{
_autoSnmpTx = autoTx;
}
}
/// <summary>
/// SNMP SET 명령 (정수 값)
/// </summary>
public void SetDataBySnmp(int mode, uint value)
{
lock (_lockObject)
{
_setSnmpMode = mode;
_setSnmpValue = value;
}
}
/// <summary>
/// SNMP SET 명령 (문자열 값)
/// </summary>
public void SetDataBySnmp(int mode, string value)
{
lock (_lockObject)
{
_setSnmpMode1 = mode;
_setSnmpStringData = value ?? "";
}
}
/// <summary>
/// 리소스 해제
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
#region PRIVATE METHODS
protected virtual void Dispose(bool disposing)
{
if (!_disposed && disposing)
{
_cancellationTokenSource?.Cancel();
try
{
_snmpTask?.Wait(1000); // 5초 대기
}
catch (OperationCanceledException)
{
// 정상적인 취소
}
catch (AggregateException ex) when (ex.InnerExceptions.Count == 1 && ex.InnerException is OperationCanceledException)
{
// 정상적인 취소
}
_cancellationTokenSource?.Dispose();
_disposed = true;
}
}
/// <summary>
/// 메인 SNMP 스레드 함수
/// </summary>
private async Task SnmpThreadFunction(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
if (string.IsNullOrEmpty(_targetIP))
{
await Task.Delay(OPERATION_SLEEP_MS, cancellationToken);
continue;
}
using (var target = CreateSnmpTarget())
{
await ProcessSnmpOperations(target, cancellationToken);
}
await Task.Delay(OPERATION_SLEEP_MS, cancellationToken);
}
catch (OperationCanceledException)
{
break;
}
catch (Exception ex)
{
LogError($"SNMP 스레드 오류: {ex.Message}");
await Task.Delay(1000, cancellationToken);
}
}
}
/// <summary>
/// SNMP 타겟 생성
/// </summary>
private UdpTarget CreateSnmpTarget()
{
var agent = new IpAddress(_targetIP);
return new UdpTarget((IPAddress)agent, SNMP_PORT, SNMP_TIMEOUT_MS, SNMP_RETRIES);
}
/// <summary>
/// SNMP 작업 처리
/// </summary>
private async Task ProcessSnmpOperations(UdpTarget target, CancellationToken cancellationToken)
{
// SET 명령 처리
if (_setSnmpMode != 0)
{
await ExecuteSetCommand(target, _setSnmpMode, _setSnmpValue, _setSnmpStringData);
_setSnmpMode = 0;
return;
}
if (_setSnmpMode1 != 0)
{
await ExecuteSetCommand(target, _setSnmpMode1, _setSnmpValue, _setSnmpStringData);
_setSnmpMode1 = 0;
return;
}
// GET 명령 처리
if (_autoSnmpTx)
{
await ExecuteGetOperations(target, cancellationToken);
}
}
/// <summary>
/// SNMP SET 명령 실행
/// </summary>
private async Task<bool> ExecuteSetCommand(UdpTarget target, int mode, uint value, string stringValue)
{
try
{
var setPdu = new Pdu(PduType.Set);
switch (mode)
{
case 1: // Reset Command
setPdu.VbList.Add(new Oid(".1.3.6.1.4.1.33.13.1.0"), new Integer32(Convert.ToInt32(value)));
break;
case 2: // Module Quantity Set
setPdu.VbList.Add(new Oid(".1.3.6.1.4.1.33.2.4.0"), new Integer32(Convert.ToInt32(value)));
break;
case 3: // Alarm Output Mode
setPdu.VbList.Add(new Oid(".1.3.6.1.4.1.33.2.5.0"), new Integer32(Convert.ToInt32(value)));
break;
case 4: // Manufacture Date
setPdu.VbList.Add(new Oid(".1.3.6.1.4.1.33.2.6.0"), new Integer32(Convert.ToInt32(value)));
break;
case 5: // BMS Serial Number
setPdu.VbList.Add(new Oid(".1.3.6.1.4.1.33.2.7.0"), new OctetString(stringValue));
break;
default:
LogError($"알 수 없는 SET 모드: {mode}");
return false;
}
var param = new AgentParameters(SnmpVersion.Ver1, new OctetString(DEFAULT_COMMUNITY));
var result = await Task.Run(() => target.Request(setPdu, param) as SnmpV1Packet);
return ProcessSetResult(result);
}
catch (Exception ex)
{
LogError($"SET 명령 실행 중 오류: {ex.Message}");
OnSetResult?.Invoke($"SET 명령 실행 실패: {ex.Message}", true);
return false;
}
}
/// <summary>
/// SET 결과 처리
/// </summary>
private bool ProcessSetResult(SnmpV1Packet result)
{
if (result == null)
{
LogError("SNMP 에이전트로부터 응답이 없습니다.");
OnSetResult?.Invoke("SNMP 에이전트 응답 없음", true);
return false;
}
if (result.Pdu.ErrorStatus != 0)
{
var errorMsg = $"SNMP 응답 오류: Error {result.Pdu.ErrorStatus} index {result.Pdu.ErrorIndex}";
LogError(errorMsg);
OnSetResult?.Invoke(errorMsg, true);
return false;
}
var resultValue = result.Pdu.VbList[0].Value.ToString();
var successMsg = $"SNMP SET 성공: {resultValue}";
OnSetResult?.Invoke(successMsg, false);
return true;
}
/// <summary>
/// SNMP GET 작업 실행
/// </summary>
private async Task ExecuteGetOperations(UdpTarget target, CancellationToken cancellationToken)
{
while (_autoSnmpTx && !cancellationToken.IsCancellationRequested)
{
if (_setSnmpMode != 0 || _setSnmpMode1 != 0)
break;
try
{
var pdu = new Pdu(PduType.Get);
pdu.VbList.Add(GetCurrentOid());
var param = new AgentParameters(SnmpVersion.Ver1, new OctetString(DEFAULT_COMMUNITY));
LogTransaction($"SEND {target.Address}: OID [{pdu.VbList[0].Oid}]");
var result = await Task.Run(() => target.Request(pdu, param) as SnmpV1Packet);
if (await ProcessGetResult(result, target))
{
_commTimeOut = 0;
_systemData.CommFail = false;
}
else
{
HandleCommunicationTimeout();
}
MoveToNextOid();
await Task.Delay(THREAD_SLEEP_MS, cancellationToken);
}
catch (Exception ex)
{
LogError($"GET 작업 중 오류: {ex.Message}");
HandleCommunicationTimeout();
break;
}
}
UpdateSystemStatus();
}
/// <summary>
/// GET 결과 처리
/// </summary>
private async Task<bool> ProcessGetResult(SnmpV1Packet result, UdpTarget target)
{
return await Task.Run(() =>
{
if (result == null)
{
LogError("SNMP 에이전트로부터 응답이 없습니다.");
return false;
}
if (result.Pdu.ErrorStatus != 0)
{
LogError($"SNMP 응답 오류: Error {result.Pdu.ErrorStatus} index {result.Pdu.ErrorIndex}");
return false;
}
LogTransaction($"RECV {target.Address}: OID [{result.Pdu.VbList[0].Oid}]: [{result.Pdu.VbList[0].Value}]");
// OID 검증 및 데이터 처리
var oidArray = (uint[])result.Pdu.VbList[0].Oid;
if (IsValidTargetOid(oidArray))
{
ProcessValidData(result, oidArray);
return true;
}
return false;
});
}
/// <summary>
/// 유효한 타겟 OID인지 확인
/// </summary>
private bool IsValidTargetOid(uint[] oidArray)
{
return oidArray.Length >= 8 &&
oidArray[0] == 1 && oidArray[1] == 3 && oidArray[2] == 6 &&
oidArray[3] == 1 && oidArray[4] == 2 && oidArray[5] == 1 && oidArray[6] == 15;
}
/// <summary>
/// 유효한 데이터 처리
/// </summary>
private void ProcessValidData(SnmpV1Packet result, uint[] oidArray)
{
try
{
if (result.Pdu.VbList[0].Value.Type == AsnType.OCTETSTRING)
{
var value = result.Pdu.VbList[0].Value.ToString();
csMakeDataFunction124050.SetSnmpData((int)oidArray[7], value, ref _systemData);
}
CalcAvgTemperatureModule(ref _systemData, (uint)_systemData.tempQty);
CheckShelfCommFail(ref _systemData);
OnUpdate?.Invoke(this, ref _systemData);
}
catch (Exception ex)
{
LogError($"데이터 처리 중 오류: {ex.Message}");
}
}
/// <summary>
/// 통신 타임아웃 처리
/// </summary>
private void HandleCommunicationTimeout()
{
_commTimeOut++;
if (_commTimeOut >= MAX_COMM_TIMEOUT)
{
_systemData.CommFail = true;
InitModuleData();
_commTimeOut = MAX_COMM_TIMEOUT;
}
}
/// <summary>
/// 시스템 상태 업데이트
/// </summary>
private void UpdateSystemStatus()
{
CheckShelfCommFail(ref _systemData);
OnUpdate?.Invoke(this, ref _systemData);
}
/// <summary>
/// 현재 OID 반환
/// </summary>
private string GetCurrentOid()
{
return _oidList?[_oidIndex] ?? "";
}
/// <summary>
/// 다음 OID로 이동
/// </summary>
private void MoveToNextOid()
{
_oidIndex = (_oidIndex + 1) % (_oidList?.Length ?? 1);
}
/// <summary>
/// 모듈 데이터 초기화
/// </summary>
private void InitModuleData()
{
if (_systemData?.ValueData == null) return;
_systemData.ValueData.voltageOfPack = 0;
_systemData.ValueData.current = 0;
_systemData.ValueData.averageCurrent = 0;
_systemData.ValueData.rSOC = 0;
_systemData.ValueData.stateOfHealth = 0;
Array.Clear(_systemData.ValueData.CellVoltage, 0, _systemData.ValueData.CellVoltage.Length);
Array.Clear(_systemData.ValueData.CellTemperature, 0, _systemData.ValueData.CellTemperature.Length);
if (_systemData.AvgData != null)
{
_systemData.AvgData.avgCellVoltage = 0;
_systemData.AvgData.diffCellVoltage = 0;
_systemData.AvgData.maxCellVoltage = 0;
_systemData.AvgData.minCellVoltage = 0;
_systemData.AvgData.maxCellNum = 0;
_systemData.AvgData.minCellNum = 0;
_systemData.AvgData.avgTemp = 0;
_systemData.AvgData.diffTemp = 0;
_systemData.AvgData.maxTemp = 0;
_systemData.AvgData.minTemp = 0;
_systemData.AvgData.maxTempNum = 0;
_systemData.AvgData.minTempNum = 0;
}
}
/// <summary>
/// 선반 통신 실패 확인
/// </summary>
private void CheckShelfCommFail(ref DeviceSystemData systemData)
{
systemData.ShelfCommFail = systemData.StatusData.batteryStatus == 0x0003;
}
/// <summary>
/// 평균 온도 계산
/// </summary>
private static void CalcAvgTemperatureModule(ref DeviceSystemData systemData, uint tempSize)
{
if (systemData?.ValueData?.CellTemperature == null || systemData.AvgData == null)
return;
var temperatures = systemData.ValueData.CellTemperature;
var validCount = Math.Min((int)tempSize, temperatures.Length);
if (validCount == 0)
{
systemData.AvgData.avgTemp = 0;
return;
}
var sum = 0;
var max = new { value = temperatures[0], index = 0 };
var min = new { value = temperatures[0], index = 0 };
for (int i = 0; i < validCount; i++)
{
var temp = temperatures[i];
sum += temp;
if (temp > max.value)
max = new { value = temp, index = i };
if (temp < min.value)
min = new { value = temp, index = i };
}
systemData.AvgData.avgTemp = (short)(sum / validCount);
systemData.AvgData.maxTemp = max.value;
systemData.AvgData.maxTempNum = max.index;
systemData.AvgData.minTemp = min.value;
systemData.AvgData.minTempNum = min.index;
}
/// <summary>
/// 트랜잭션 로그
/// </summary>
private void LogTransaction(string message)
{
try
{
var logMessage = csLog.trx_msg_print(message, 1);
OnSetResult?.Invoke(logMessage, false);
}
catch
{
// 로그 실패 시 무시
}
}
/// <summary>
/// 오류 로그
/// </summary>
private void LogError(string message)
{
try
{
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
var logMessage = $"[{timestamp}] {message}";
OnSetResult?.Invoke(logMessage, true);
}
catch
{
// 로그 실패 시 무시
}
}
#endregion
}
}

View File

@@ -0,0 +1,765 @@
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;
using DevExpress.XtraGauges.Core.Model;
namespace LFP_Manager.Threads
{
class CsUartThread124050
{
#region VARIABLES
private readonly CommConfig Config;
private DeviceSystemData SystemData;
private Thread serialComm = null;
private SerialPort sPort = null;
private bool SerialPortThreadEnd = true;
public int SystemId = 0;
private bool UartPolling = false;
private bool AutoUartTx = true;
private int addr_ch = 0;
private ushort RequestRegAddr = 0x0000; //Byul Init 0x0000
private ushort RequestRegLen = 50;
private bool rFlag = false;
private int rFlag2 = 0;
private int wFlag = 0;
private ushort ReadRegAddr = 0x0000; //Byul Init 0x0000
private ushort ReadRegLen = 0x0000; //Byul Init 0x0000
private ushort WriteRegAddr = 0x0000; //Byul Init 0x0000
private short WriteCoilRegData = 0;
private byte[] WriteRegData;
private TUartTxBuff uartTxBuff = null;
public event UartDataUpdate OnUpdate = null;
public event UartDataRecv OnDataRecv = null;
public event UartDataPrint OnPrint = null;
#endregion
#region CONSTRUCTORS
public CsUartThread124050(int sId, CommConfig aConfig, ref DeviceSystemData aSystemData)
{
SystemId = sId;
Config = aConfig;
SystemData = aSystemData;
uartTxBuff = new TUartTxBuff();
serialComm = new Thread(uartCommThread);
}
public void disposeThread()
{
if (sPort != null)
{
if (sPort.IsOpen)
{
sPort.Close();
}
sPort = null;
}
SerialPortThreadEnd = true;
if (serialComm != null)
{
if (serialComm.IsAlive)
{
serialComm.Abort();
}
serialComm = null;
}
}
public bool Start(ref CommConfig aConfig, int sId, bool aPolling)
{
bool result = false;
SystemId = sId;
UartPolling = aPolling;
if (Open(aConfig.UartPort, 115200)) //Byul Init 9600
{
SerialPortThreadEnd = false;
serialComm.Start();
result = true;
}
return result;
}
public void Stop()
{
SerialPortThreadEnd = true;
Close();
}
#endregion
#region COMMPORT CONTROLS
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);
for (int i = 0; i < rLen; i++)
{
PutBuff(sRead[i]);
}
}
catch (Exception)
{
}
}
private void sErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
{
//
//csMakeDataFunction.SetData()
}
private void sPinChanged(object sender, System.IO.Ports.SerialPinChangedEventArgs e)
{
//
}
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
{
sPort.Open();
}
catch (Exception ex)
{
throw new Exception("Error Open - " + ex.Message);
}
return sPort.IsOpen;
}
private void Close()
{
if (sPort != null)
{
if (sPort.IsOpen)
{
sPort.Close();
}
sPort = null;
}
}
#endregion
#region PUBLIC FUNCTION
public void SetPolling(bool flag, int sId, ref DeviceSystemData aSystemData)
{
SystemId = sId;
UartPolling = flag;
SystemData = aSystemData;
SystemData.mNo = SystemId;
}
public void SetAutoTx(bool 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)
{
WriteRegAddr = WriteAddr;
TUartTRxData uartTRxData = new TUartTRxData();
uartTRxData.type = type;
//uartTRxData.data = csSerialCommFunction.MakeWriteRegisterData((ushort)SystemId, WriteRegAddr, WriteData);
uartTRxData.data = WriteData;
uartTRxData.length = uartTRxData.data.Length;
uartTxBuff?.PutBuff(uartTRxData);
}
public void SetReadReg(ushort ReadAddr, ushort ReadLen, bool ReplyFlag)
{
wFlag = 4;
ReadRegAddr = ReadAddr;
ReadRegLen = ReadLen;
}
public void SetParam(ushort WriteAddr, short[] WriteData)
{
wFlag = 1;
WriteRegAddr = WriteAddr;
TUartTRxData uartTRxData = new TUartTRxData();
uartTRxData.type = wFlag;
uartTRxData.data = csSerialCommFunction.MakeWriteRegisterData((ushort)SystemId, WriteRegAddr, WriteData);
uartTRxData.length = uartTRxData.data.Length;
uartTxBuff?.PutBuff(uartTRxData);
}
public void SendProcessFromApp(int sId, int mode, int index, int flag, ref DeviceParamData aParam, ref DeviceCalibration aCalib)
{
short[] data = null;
switch (mode)
{
case csConstData.UART_PARAM_LIST.CELL_UNDER_VOLTAGE: // Cell Under Volatge Parameter
data = new short[1];
data[0] = aParam.CellUnderVoltageWarning; SetParam((ushort)(mode + 0), data);
data[0] = aParam.CellUnderVoltageTrip; SetParam((ushort)(mode + 1), data);
data[0] = aParam.CellUnderVoltageRelease; SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.CELL_OVER_VOLTAGE: // Cell Over Volatge Parameter
data = new short[1];
data[0] = aParam.CellOverVoltageWarning; SetParam((ushort)(mode + 0), data);
data[0] = aParam.CellOverVoltageTrip; SetParam((ushort)(mode + 1), data);
data[0] = aParam.CellOverVoltageRelease; SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.PACK_UNDER_VOLTAGE: // Pack Under Volatge Parameter
data = new short[1];
data[0] = (short)(aParam.SysUnderVoltageWarning * 10); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.SysUnderVoltageTrip * 10); SetParam((ushort)(mode + 1), data);
data[0] = (short)(aParam.SysUnderVoltageRelease * 10); SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.PACK_OVER_VOLTAGE: // Pack Over Volatge Parameter
data = new short[1];
data[0] = (short)(aParam.SysOverVoltageWarning * 10); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.SysOverVoltageTrip * 10); SetParam((ushort)(mode + 1), data);
data[0] = (short)(aParam.SysOverVoltageRelease * 10); SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.CHG_LOW_TEMPERATURE: // Charge Low Temperature Parameter
data = new short[1];
data[0] = (short)(aParam.ChaLowTempWarning + 50); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.ChaLowTempTrip + 50); SetParam((ushort)(mode + 1), data);
data[0] = (short)(aParam.ChaLowTempRelease + 50); SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.CHG_HIGH_TEMPERATURE: // Pack High Temperature Parameter
data = new short[1];
data[0] = (short)(aParam.ChaHighTempWarning + 50); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.ChaHighTempTrip + 50); SetParam((ushort)(mode + 1), data);
data[0] = (short)(aParam.ChaHighTempRelease + 50); SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.DCH_LOW_TEMPERATURE: // Charge Low Temperature Parameter
data = new short[1];
data[0] = (short)(aParam.DchLowTempWarning + 50); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.DchLowTempTrip + 50); SetParam((ushort)(mode + 1), data);
data[0] = (short)(aParam.DchLowTempRelease + 50); SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.DCH_HIGH_TEMPERATURE: // Pack High Temperature Parameter
data = new short[1];
data[0] = (short)(aParam.DchHighTempWarning + 50); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.DchHighTempTrip + 50); SetParam((ushort)(mode + 1), data);
data[0] = (short)(aParam.DchHighTempRelease + 50); SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.CHG_OVER_CURRENT: // Charge Over Current Parameter
data = new short[1];
data[0] = (short)(aParam.ChaOverCurrentReleaseTime * 1); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.ChaOverCurrentTrip1 * 10); SetParam((ushort)(mode + 2), data);
data[0] = (short)(aParam.ChaOverCurrentTrip2 * 10); SetParam((ushort)(mode + 5), data);
break;
case csConstData.UART_PARAM_LIST.DCH_OVER_CURRENT: // Discharge Over Current Parameter
data = new short[1];
data[0] = (short)(aParam.DchOverCurrentReleaseTime * 1); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.DchOverCurrentTrip1 * 10); SetParam((ushort)(mode + 2), data);
data[0] = (short)(aParam.DchOverCurrentTrip2 * 10); SetParam((ushort)(mode + 5), data);
break;
case csConstData.UART_PARAM_LIST.LOW_CAPACITY:
data = new short[1];
data[0] = aParam.LowSocWarning; SetParam((ushort)(mode + 0), data);
break;
case csConstData.UART_PARAM_LIST.DEFAULT_PARAM: // Default Parameter
int i = 0;
Forms.fmxWait WaitForm = new Forms.fmxWait();
WaitForm.StartPosition = FormStartPosition.CenterScreen;
try
{
data = new short[1];
i = csConstData.UART_PARAM_LIST.CELL_UNDER_VOLTAGE;
data[0] = 0; SetParam((ushort)(i + 0), data);
data[0] = 0; SetParam((ushort)(i + 1), data);
data[0] = 0; SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.PACK_UNDER_VOLTAGE;
data[0] = 0; SetParam((ushort)(i + 0), data);
data[0] = 0; SetParam((ushort)(i + 1), data);
data[0] = 0; SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.CELL_OVER_VOLTAGE;
data[0] = 0; SetParam((ushort)(i + 0), data);
data[0] = 0; SetParam((ushort)(i + 1), data);
data[0] = 0; SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.PACK_OVER_VOLTAGE;
data[0] = 0; SetParam((ushort)(i + 0), data);
data[0] = 0; SetParam((ushort)(i + 1), data);
data[0] = 0; SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.CHG_OVER_CURRENT;
data[0] = 0; SetParam((ushort)(i - 2), data);
data[0] = 0; SetParam((ushort)(i + 0), data);
data[0] = 0; SetParam((ushort)(i + 2), data);
data[0] = 0; SetParam((ushort)(i + 5), data);
data[0] = 0; SetParam((ushort)(i + 8), data);
data[0] = 0; SetParam((ushort)(i + 9), data);
i = csConstData.UART_PARAM_LIST.DCH_OVER_CURRENT;
data[0] = 0; SetParam((ushort)(i - 2), data);
data[0] = 0; SetParam((ushort)(i + 0), data);
data[0] = 0; SetParam((ushort)(i + 2), data);
data[0] = 0; SetParam((ushort)(i + 5), data);
data[0] = 0; SetParam((ushort)(i + 8), data);
data[0] = 0; SetParam((ushort)(i + 9), data);
i = csConstData.UART_PARAM_LIST.CHG_LOW_TEMPERATURE;
data[0] = 0; SetParam((ushort)(i + 0), data);
data[0] = 0; SetParam((ushort)(i + 1), data);
data[0] = 0; SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.CHG_HIGH_TEMPERATURE;
data[0] = 0; SetParam((ushort)(i + 0), data);
data[0] = 0; SetParam((ushort)(i + 1), data);
data[0] = 0; SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.DCH_LOW_TEMPERATURE;
data[0] = 0; SetParam((ushort)(i + 0), data);
data[0] = 0; SetParam((ushort)(i + 1), data);
data[0] = 0; SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.DCH_HIGH_TEMPERATURE;
data[0] = 0; SetParam((ushort)(i + 0), data);
data[0] = 0; SetParam((ushort)(i + 1), data);
data[0] = 0; SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.LOW_CAPACITY;
data[0] = 0; SetParam((ushort)(i + 0), data);
i = csConstData.UART_PARAM_LIST.ENV_LOW_TEMPERATURE;
data[0] = 0; SetParam((ushort)(i + 0), data);
data[0] = 0; SetParam((ushort)(i + 1), data);
data[0] = 0; SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.ENV_HIGH_TEMPERATURE;
data[0] = 0; SetParam((ushort)(i + 0), data);
data[0] = 0; SetParam((ushort)(i + 1), data);
data[0] = 0; SetParam((ushort)(i + 2), data);
}
catch (Exception)
{
}
break;
case 15: // Capcity change
data = new short[1];
i = csConstData.UART_PARAM_LIST.DESIGN_CAPACITY;
data[0] = (short)aCalib.CapCalib.DesignCapacity; SetParam((ushort)(i + 0), data);
i = csConstData.UART_PARAM_LIST.SOC_VALUE;
data[0] = (short)aCalib.CapCalib.SocValue; SetParam((ushort)(i + 0), data);
break;
case 16: // Charge Mode
data = new short[1];
i = csConstData.UART_CALIB_ADDR_LIST.CHAGE_MODE;
data[0] = (short)aCalib.ChaMode.Mode; SetParam((ushort)(i + 0), data);
data[0] = (short)aCalib.ChaMode.Value; SetParam((ushort)(i + 1), data);
break;
case 17: // BMS DateTime Set
data = new short[2];
i = csConstData.UART_CALIB_ADDR_LIST.BMS_DATETIME;
data[0] = (short)aCalib.BmsDateTime.sValue[0];
data[1] = (short)aCalib.BmsDateTime.sValue[1]; SetParam((ushort)(i + 0), data);
break;
case 18:
data = new short[1];
i = csConstData.UART_CALIB_ADDR_LIST.ANTI_THEFT_GYRO;
data[0] = (short)aCalib.AntiTheft.GyroScope; SetParam((ushort)(i + 0), data);
break;
case 19: // Clear Protect
data = new short[1];
i = csConstData.UART_CALIB_ADDR_LIST.ANTI_THEFT_GYRO;
data[0] = (short)0; SetParam((ushort)(i + 0), data);
data[0] = (short)aCalib.AntiTheft.GyroScope; SetParam((ushort)(i + 0), data);
break;
case 20:
data = new short[1];
i = csConstData.UART_CALIB_ADDR_LIST.ANTI_THEFT_COMM;
data[0] = (short)aCalib.AntiTheft.Comm; SetParam((ushort)(i + 0), data);
break;
case 21: // Cell Balancing Voltage
data = new short[1];
i = csConstData.UART_CALIB_ADDR_LIST.BAL_VOLT;
data[0] = (short)aCalib.BalCalib.Volt; SetParam((ushort)(i + 0), data);
break;
case 22: // Cell Balancing Diff
data = new short[1];
i = csConstData.UART_CALIB_ADDR_LIST.BAL_DIFF;
data[0] = (short)aCalib.BalCalib.Diff; SetParam((ushort)(i + 0), data);
break;
default:
break;
}
}
#endregion
#region RX BUFFERING
private const int BUFFER_SIZE = 512;
private readonly byte[] rBuffer = new byte[BUFFER_SIZE];
private int rBufStart = 0;
private int rBufEnd = 0;
private void PutBuff(byte c)
{
rBuffer[rBufStart++] = c;
rBufStart %= BUFFER_SIZE;
if (rBufStart == rBufEnd)
{
rBufEnd++;
rBufEnd %= BUFFER_SIZE;
}
}
private int GetBuff()
{
int result = 0;
if (rBufStart != rBufEnd)
{
result = 0x0100 + rBuffer[rBufEnd++];
rBufEnd %= BUFFER_SIZE;
}
return result;
}
private void FlushBuff()
{
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[] MakeTxDataVision(ref bool wData)
{
byte[] sData = null;
rFlag2 = 0;
if ((uartTxBuff != null) && (uartTxBuff.CheckBuff()))
{
TUartTRxData sBuff = uartTxBuff.GetBuff();
if (sBuff != null)
{
sData = sBuff.data;
wData = true;
rFlag = true;
rFlag2 = sBuff.type;
}
}
else if (wFlag == 2)
{
sData = csSerialCommFunction.MakeWriteCoilData((ushort)SystemId, WriteRegAddr, WriteCoilRegData);
if (wFlag != 0) wFlag = 0;
rFlag = true;
}
else if (wFlag == 3)
{
sData = WriteRegData;
if (wFlag != 0) wFlag = 0;
rFlag = true;
}
else if (wFlag == 4)
{
sData = csSerialCommFunction.MakeReadRegisterData((ushort)SystemId, csSerialCommFunction.READ_HOLDING_REG, ReadRegAddr, ReadRegLen);
if (wFlag != 0) wFlag = 0;
rFlag = true;
}
else
{
if (UartPolling && AutoUartTx)
{
ushort sCmd;
switch (addr_ch)
{
case 0:
addr_ch = 1;
RequestRegAddr = 0x0000; //Byul Init 0x0000
RequestRegLen = 0x0040;
sCmd = csSerialCommFunction.READ_HOLDING_REG;
rFlag = true;
break;
case 1:
addr_ch = 2;
RequestRegAddr = 0x0040;
RequestRegLen = 0x0040;
sCmd = csSerialCommFunction.READ_HOLDING_REG;
rFlag = true;
break;
case 2:
addr_ch = 3;
RequestRegAddr = 0x0080;
RequestRegLen = 0x0040;
sCmd = csSerialCommFunction.READ_HOLDING_REG;
rFlag = true;
break;
case 3:
if (Config.ModuleQty > 1)
{
SystemId++;
if (SystemId > Config.ModuleQty)
{
SystemId = 1;
}
}
addr_ch = 0;
sCmd = csSerialCommFunction.NO_CMD;
rFlag = false;
break;
default:
addr_ch = 0;
RequestRegAddr = 0x0000; //Byul Init 0x0000
RequestRegLen = 100;
sCmd = csSerialCommFunction.READ_HOLDING_REG;
break;
}
if (sCmd == csSerialCommFunction.NO_CMD)
{
sData = null;
}
else
{
sData = csSerialCommFunction.MakeReadRegisterData((ushort)SystemId, sCmd, RequestRegAddr, RequestRegLen);
}
}
}
return sData;
}
#endregion
#region COMM THREAD
private readonly byte[] ReadBuf = new byte[BUFFER_SIZE];
ushort rPosition = 0;
bool BuffStart = false;
private void RecvPacketInit()
{
BuffStart = false;
rPosition = 0;
}
private void uartCommThread()
{
int RecvTimeout = Config.RecvWaitTime;
int getData = 0;
byte cData = 0;
int TimeOutCount = 0;
StartSend:
while (SerialPortThreadEnd == false)
{
if ((sPort == null) || (sPort.IsOpen == false)) continue;
bool wMode = false;
byte[] txData = MakeTxDataVision(ref wMode);
if (txData != null)
{
FlushBuff();
sPort.Write(txData, 0, txData.Length);
OnPrint?.Invoke(this, csLog.trx_data_print(txData, txData.Length, 0));
}
if (rFlag == true)
{
RecvPacketInit();
DateTime rDateTime = DateTime.Now;
while (true)
{
DateTime nDateTime = rDateTime.AddMilliseconds(RecvTimeout);
if (nDateTime < DateTime.Now) break;
if (((getData = GetBuff()) & 0x0100) != 0x0000)
{
rDateTime = DateTime.Now;
cData = (byte)(getData & 0x00FF);
if (rPosition >= BUFFER_SIZE) RecvPacketInit();
if (BuffStart == false)
{
if ((cData == (byte)SystemId) || (cData == (byte)0x7F))
{
rPosition = 0;
ReadBuf[rPosition++] = cData;
BuffStart = true;
}
}
else
{
ReadBuf[rPosition++] = cData;
switch (csSerialCommFunction.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 = 0;
int mID = ReadBuf[0];
if (mID > 0) mID--;
SystemData.CommFail = false;
SystemData.ShelfCommFail = false;
if (rFlag2 == 0)
{
short[] result_code = csSerialCommFunction124050.SerialRxProcess(ReadBuf, RequestRegAddr, rPosition, ref SystemData);
OnUpdate?.Invoke(this, ref SystemData);
}
else
{
rFlag2 = 0;
wMode = false;
WriteRegAddr = 0;
if (OnDataRecv != null)
{
byte[] adata = new byte[rPosition + 1];
for (int j = 0; j < adata.Length; j++) { adata[j] = ReadBuf[j]; }
OnDataRecv(adata);
}
}
rFlag = false;
Thread.Sleep(100);
goto StartSend;
case 2: // Fw Update Packet OK
OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1));
TimeOutCount = 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;
}
}
}
else
{
Thread.Sleep(1);
}
}
if (rPosition > 0)
{
Thread.Sleep(1);
}
else
{
WriteRegAddr = 0;
TimeOutCount++;
if (TimeOutCount >= 5)
{
TimeOutCount = 5;
//SystemData[0].CommFail = true;
if (SystemData.ShelfCommFail == false)
{
SystemData.ShelfCommFail = true;
csUtils.DataInit(Config, ref SystemData);
}
}
Thread.Sleep(100);
}
OnUpdate?.Invoke(this, ref SystemData);
Thread.Sleep(1);
}
else
{
Thread.Sleep(100);
} /* if (rFlag == true) */
rPosition = 0;
}
}
#endregion
}
}

View File

@@ -0,0 +1,574 @@
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;
using DevExpress.XtraGauges.Core.Model;
namespace LFP_Manager.Threads
{
#region DELEGATE
public delegate void UartDataUpdateRS485(object sender, ref DeviceSystemData[] aSystemData);
public delegate void UartDataRecvRS485(byte[] data);
public delegate void UartDataPrintRS485(object sender, string msg);
#endregion
class CsUartThreadDelta
{
#region VARIABLES
private readonly CommConfig Config;
private DeviceSystemData[] SystemData;
private Thread serialComm = null;
private SerialPort sPort = null;
private bool SerialPortThreadEnd = true;
public int ModuleID = 1;
private bool UartPolling = false;
private bool AutoUartTx = true;
private int addr_ch = 0;
private ushort RequestRegAddr = 0x0000; //Byul Init 0x0000
private ushort RequestRegLen = 50;
private bool rFlag = false;
private int wFlag = 0;
private int rFlag2 = 0;
private ushort ExtReqRegAddr = 0x0000;
private ushort WriteRegAddr = 0x0000; //Byul Init 0x0000
private short WriteCoilRegData = 0;
private byte[] WriteRegData;
private short WriteParamRegData;
private TUartTxBuff UartTxBuff;
public event UartDataUpdateRS485 OnUpdate = null;
public event UartDataRecvRS485 OnDataRecv = null;
public event UartDataPrintRS485 OnPrint = null;
#endregion
#region CONSTRUCTORS
public CsUartThreadDelta(int mID, CommConfig aConfig, ref DeviceSystemData[] aSystemData)
{
ModuleID = mID;
Config = aConfig;
SystemData = aSystemData;
UartTxBuff = new TUartTxBuff();
serialComm = new Thread(uartCommThread);
}
public void disposeThread()
{
if (sPort != null)
{
if (sPort.IsOpen)
{
sPort.Close();
}
sPort = null;
}
SerialPortThreadEnd = true;
if (serialComm != null)
{
if (serialComm.IsAlive)
{
serialComm.Abort();
}
serialComm = null;
}
}
public bool Start(ref CommConfig aConfig, int mID, bool aPolling)
{
bool result = false;
ModuleID = mID;
UartPolling = aPolling;
if (Open(aConfig.UartPort, 9600)) //Byul Init 9600
{
SerialPortThreadEnd = false;
serialComm.Start();
result = true;
}
return result;
}
public void Stop()
{
SerialPortThreadEnd = true;
Close();
}
#endregion
#region COMMPORT CONTROLS
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);
for (int i = 0; i < rLen; i++)
{
PutBuff(sRead[i]);
}
}
catch (Exception)
{
}
}
private void sErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
{
//
//csMakeDataFunction.SetData()
}
private void sPinChanged(object sender, System.IO.Ports.SerialPinChangedEventArgs e)
{
//
}
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
{
sPort.Open();
}
catch (Exception ex)
{
throw new Exception("Error Open - " + ex.Message);
}
return sPort.IsOpen;
}
private void Close()
{
if (sPort != null)
{
if (sPort.IsOpen)
{
sPort.Close();
}
sPort = null;
}
}
#endregion
#region PUBLIC FUNCTION
public void SetPolling(bool flag, int mID, ref DeviceSystemData[] aSystemData)
{
ModuleID = mID;
UartPolling = flag;
SystemData = aSystemData;
SystemData[0].mNo = ModuleID;
}
public void SetAutoTx(bool 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)
{
WriteRegAddr = WriteAddr;
TUartTRxData uartTRxData = new TUartTRxData();
uartTRxData.type = type;
//uartTRxData.data = csSerialCommFunction.MakeWriteRegisterData((ushort)SystemId, WriteRegAddr, WriteData);
uartTRxData.data = WriteData;
uartTRxData.length = uartTRxData.data.Length;
UartTxBuff?.PutBuff(uartTRxData);
}
public void SetParam(ushort WriteAddr, short WriteData)
{
byte[] sData = CsSerialCommFunctionDelta.MakeWriteRegisterData((ushort)ModuleID, WriteAddr, WriteData);
if (sData != null)
{
TUartTRxData aData = new TUartTRxData();
aData.length = sData.Length;
aData.data = sData;
UartTxBuff.PutBuff(aData);
}
}
public void SetReadWriteParam(ushort WriteAddr, short WriteData)
{
byte[] sData = CsSerialCommFunctionDelta.MakeReadWriteRegisterData((ushort)ModuleID, WriteAddr, WriteData);
if (sData != null)
{
TUartTRxData aData = new TUartTRxData();
aData.length = sData.Length;
aData.data = sData;
ExtReqRegAddr = WriteAddr;
UartTxBuff.PutBuff(aData);
}
}
#endregion
#region RX BUFFERING
private const int BUFFER_SIZE = 512;
private readonly byte[] rBuffer = new byte[BUFFER_SIZE];
private int rBufStart = 0;
private int rBufEnd = 0;
private void PutBuff(byte c)
{
rBuffer[rBufStart++] = c;
rBufStart %= BUFFER_SIZE;
if (rBufStart == rBufEnd)
{
rBufEnd++;
rBufEnd %= BUFFER_SIZE;
}
}
private int GetBuff()
{
int result = 0;
if (rBufStart != rBufEnd)
{
result = 0x0100 + rBuffer[rBufEnd++];
rBufEnd %= BUFFER_SIZE;
}
return result;
}
private void FlushBuff()
{
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;
if ((UartTxBuff != null) && (UartTxBuff.CheckBuff()))
{
TUartTRxData sBuff = UartTxBuff.GetBuff();
if (sBuff != null)
{
sData = sBuff.data;
wData = true;
rFlag = true;
rFlag2 = sBuff.type;
RequestRegAddr = ExtReqRegAddr;
}
}
else
{
if (AutoUartTx && UartPolling)
{
ushort sCmd;
switch (addr_ch)
{
case 0: // Battery Status Data
addr_ch = 1;
RequestRegAddr = 0x0FFF; //Byul Init 0x0000
RequestRegLen = 0x27;
sCmd = CsSerialCommFunctionDelta.READ_INPUT_REG; // Command 0x04
rFlag = true;
break;
case 1: // Gyroscope Data
addr_ch = 2;
RequestRegAddr = 0x4000;
RequestRegLen = 7;
sCmd = CsSerialCommFunctionDelta.READ_INPUT_REG; // Command 0x17
rFlag = true;
break;
case 2:
addr_ch = 3;
RequestRegAddr = 0x3000;
RequestRegLen = 3;
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 4:
addr_ch = 5;
RequestRegAddr = 100;
RequestRegLen = 30;
sCmd = CsSerialCommFunctionDelta.READ_HOLDING_REG; // Command 0x03
rFlag = true;
break;
case 5:
if (Config.ModuleQty > 1)
{
ModuleID++;
if (ModuleID > Config.ModuleQty)
{
ModuleID = 1;
}
}
addr_ch = 0;
sCmd = CsSerialCommFunctionDelta.NO_CMD;
rFlag = false;
break;
default:
addr_ch = 0;
RequestRegAddr = 0x0FFF; //Byul Init 0x0000
RequestRegLen = 27;
sCmd = CsSerialCommFunctionDelta.READ_INPUT_REG; // Command 0x04
rFlag = true;
break;
}
if (sCmd == CsSerialCommFunctionDelta.NO_CMD)
{
sData = null;
}
else if (sCmd == CsSerialCommFunctionDelta.READ_DEV_ID)
{
sData = CsSerialCommFunctionDelta.MakeReadDevIdRegReqData((ushort)ModuleID, sCmd, RequestRegAddr);
}
else
{
sData = CsSerialCommFunctionDelta.MakeReadRegisterData((ushort)ModuleID, sCmd, RequestRegAddr, RequestRegLen);
}
}
}
return sData;
}
#endregion
#region COMM THREAD
private readonly byte[] ReadBuf = new byte[BUFFER_SIZE];
ushort rPosition = 0;
bool BuffStart = false;
private void RecvPacketInit()
{
BuffStart = false;
rPosition = 0;
}
private void uartCommThread()
{
int RecvTimeout = Config.RecvWaitTime;
int getData = 0;
byte cData = 0;
int[] TimeOutCount = new int[csConstData.SystemInfo.MAX_MODULE_SIZE];
StartSend:
while (SerialPortThreadEnd == false)
{
if ((sPort == null) || (sPort.IsOpen == false)) continue;
FlushBuff();
byte[] txData = MakeTxDataDelta(false);
if (sPort == null) return;
if (txData != null)
{
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)
{
DateTime nDateTime = rDateTime.AddMilliseconds(RecvTimeout);
if (nDateTime < DateTime.Now) break;
if (((getData = GetBuff()) & 0x0100) != 0x0000)
{
rDateTime = DateTime.Now;
cData = (byte)(getData & 0x00FF);
if (rPosition >= BUFFER_SIZE) RecvPacketInit();
if (BuffStart == false)
{
if ((cData == (byte)ModuleID) || (cData == (byte)0x7F))
{
rPosition = 0;
ReadBuf[rPosition++] = cData;
BuffStart = true;
}
}
else
{
ReadBuf[rPosition++] = cData;
switch (CsSerialCommFunctionDelta.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 = CsSerialCommFunctionDelta.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);
}
else
{
Thread.Sleep(1);
}
}
if (rPosition > 0)
{
OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1));
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);
}
else
{
Thread.Sleep(10);
} /* if (rFlag == true) */
rPosition = 0;
Thread.Sleep(100);
}
}
#endregion
}
}

View File

@@ -0,0 +1,315 @@
using LFP_Manager.DataStructure;
using LFP_Manager.Function;
using LFP_Manager.Utils;
using System;
using System.Data;
using System.Data.SQLite;
using System.Threading;
using System.Windows.Forms;
namespace LFP_Manager.Threads
{
public delegate void DbDataPrint(object sender, string msg);
class csDbThread
{
#region VARIABLES
private CommConfig Config = new CommConfig();
private DeviceSystemData[] SystemData;
private short[] Status, oldStatus;
private Thread dbProc = null;
private bool Active = false;
private int mQty = 1;
private int ModuleID = 1;
////////////////////////////////////////
private bool DbThreadEnd = true;
public event DbDataPrint OnPrint = null;
#endregion
#region CONSTRUCTORS
public csDbThread(int mID, CommConfig aConfig, DeviceSystemData[] aSystemData)
{
ModuleID = mID;
Status = new short[2];
oldStatus = new short[2];
Config = aConfig;
SystemData = aSystemData;
dbProc = new Thread(dbThreadProcess);
}
public void disposeThread()
{
DbThreadEnd = true;
if (dbProc != null)
{
if (dbProc.IsAlive)
{
dbProc.Abort();
}
dbProc = null;
}
}
public unsafe bool Start(int mID, CommConfig aConfig)
{
bool result = false;
ModuleID = mID;
Config = aConfig;
switch (Config.CommType)
{
case csConstData.CommType.COMM_UART: // RS-232
mQty = 1;
break;
case csConstData.CommType.COMM_RS485: // RS-485
mQty = Config.ModuleQty;
break;
case csConstData.CommType.COMM_SNMP: // SNMP
mQty = 1;
break;
default:
mQty = 1;
break;
}
// DB Create with Path Create
csHistoryFunction.DbCreate(System.IO.Path.GetDirectoryName(Application.ExecutablePath));
try
{
DbThreadEnd = false;
dbProc.Start();
Active = true;
}
catch (Exception ex)
{
OnPrint?.Invoke(this, ex.Message);
}
return result;
}
public void Stop()
{
DbThreadEnd = true;
Active = false;
}
public void UpdateStatus(short st1, short st2)
{
Status[0] = st1;
Status[1] = st2;
}
#endregion
#region UPDATE DATA
public void UpdateData(int mID, DeviceSystemData[] aSystemData)
{
ModuleID = mID;
SystemData = aSystemData;
}
#endregion
#region MAKE ALARM HISTORY
private void CheckAlarm()
{
bool[] Data1 = csUtils.Int16ToBitArray((short)Status[0]);
bool[] Data2 = csUtils.Int16ToBitArray((short)Status[1]);
bool[] oData1 = csUtils.Int16ToBitArray((short)oldStatus[0]);
bool[] oData2 = csUtils.Int16ToBitArray((short)oldStatus[1]);
// Cell Over Voltage
if (oData2[0] != Data2[0])
{
if (Data2[0] == true)
{
IDInsert("", csDbConstData.DB_ALARM.CELL_UNDER_VOLTAGE, csDbConstData.DB_ALARM.FLAG_TRIP);
}
else
{
if (oData1[0] != Data1[0])
{
if (Data1[0] == true)
IDInsert("", csDbConstData.DB_ALARM.CELL_UNDER_VOLTAGE, csDbConstData.DB_ALARM.FLAG_WARNING);
else
IDInsert("", csDbConstData.DB_ALARM.CELL_UNDER_VOLTAGE, csDbConstData.DB_ALARM.FLAG_RELEASE);
}
else
{
if (Data1[0] == false)
IDInsert("", csDbConstData.DB_ALARM.CELL_UNDER_VOLTAGE, csDbConstData.DB_ALARM.FLAG_RELEASE);
}
}
}
else
{
if (oData1[0] != Data1[0])
{
if (Data1[0] == true)
IDInsert("", csDbConstData.DB_ALARM.CELL_UNDER_VOLTAGE, csDbConstData.DB_ALARM.FLAG_WARNING);
else
IDInsert("", csDbConstData.DB_ALARM.CELL_UNDER_VOLTAGE, csDbConstData.DB_ALARM.FLAG_RELEASE);
}
}
oldStatus = Status;
}
#endregion
#region DB INSERT DATA
private void IDInsert(string mPath, int aCode, int fCode)
{
//string dbFilename = mPath + csDbConstData.DataBase.FileName;
string dbFilename = System.IO.Path.GetDirectoryName(Application.ExecutablePath) + csDbConstData.DataBase.FileName;
// Open database
string strConn = @"Data Source=" + dbFilename;
using (var connection = new SQLiteConnection(strConn))
{
connection.Open();
try
{
// Insert data
using (SQLiteCommand command = connection.CreateCommand())
{
command.CommandText = "BEGIN;"; //명시적 트렌젝션 시작
command.ExecuteNonQuery();
//sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");";
command.CommandText = "INSERT INTO " + csDbConstData.DataBase.TableName + "(HTime, model, sno, alarm_name, alarm_code, flag_name, flag, param1, param2) "
+ " Values (@HTime, @model, @sno, @alarm_name, @alarm_code, @flag_name, @flag, @param1, @param2);";
SQLiteParameter[] p = new SQLiteParameter[]
{
new SQLiteParameter("@HTime", DbType.DateTime),
new SQLiteParameter("@model", DbType.String),
new SQLiteParameter("@sno", DbType.Int16),
new SQLiteParameter("@alarm_name", DbType.String),
new SQLiteParameter("@alarm_code", DbType.Int16),
new SQLiteParameter("@flag_name", DbType.String),
new SQLiteParameter("@flag", DbType.Int16),
new SQLiteParameter("@param1", DbType.Decimal),
new SQLiteParameter("@param2", DbType.Decimal),
}; // end SQLiteParameter
command.Parameters.AddRange(p);
int result = 0;
p[0].Value = DateTime.Now; // DateTime
p[1].Value = "AAA"; // Model Name
p[2].Value = 1; // System No
p[3].Value = csDbConstData.DB_ALARM.ALARM_NAME[aCode]; // alarm_name
p[4].Value = aCode; // alarm_code
p[5].Value = csDbConstData.DB_ALARM.FLAG_NAME[fCode]; // flag_name
p[6].Value = fCode; // flag_code
p[7].Value = 0.0; // param1
p[8].Value = 0.0; // param2
try
{
result = command.ExecuteNonQuery();
}
catch (Exception)
{
}
command.CommandText = "COMMIT;"; //명시적 트렌젝션 시작
}
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
}
finally
{
connection.Close();
}
}
}
#endregion
#region DB THREAD
unsafe private void dbThreadProcess()
{
DateTime bakDateTime = DateTime.Now;
int ss = Config.DbLogPeriod;
while (DbThreadEnd == false)
{
if (Active)
{
DateTime cDate = DateTime.Now;
if (
((bakDateTime.Minute != cDate.Minute)
|| (bakDateTime.Second != cDate.Second))
&& ((cDate.Second % ss) == 0)
)
{
// Database Log Process
try
{
string ModelName;
ModelName = csConstData.MODEL_STR[Config.UartModelIndex];
csDbUtils.LogDbCreate(ModelName);
switch (Config.CommType)
{
case csConstData.CommType.COMM_UART:
SystemData[ModuleID - 1].mNo = ModuleID;
csDbProcess.BmsLogDataInsert(ModelName, ref SystemData[ModuleID - 1], cDate, 1000);
break;
case csConstData.CommType.COMM_RS485:
if (mQty > 1)
{
for (int i = 0; i < mQty; i++)
{
SystemData[i].mNo = i + 1;
csDbProcess.BmsLogDataInsert(ModelName, ref SystemData[i], cDate, 1000);
}
}
else
{
SystemData[ModuleID - 1].mNo = ModuleID;
csDbProcess.BmsLogDataInsert(ModelName, ref SystemData[ModuleID - 1], cDate, 1000);
}
break;
case csConstData.CommType.COMM_SNMP:
SystemData[ModuleID - 1].mNo = ModuleID;
csDbProcess.BmsLogDataInsert(ModelName, ref SystemData[ModuleID - 1], cDate, 1000);
break;
default:
break;
}
}
catch (Exception)
{
}
bakDateTime = cDate;
}
}
Thread.Sleep(100);
}
}
#endregion
}
}

View File

@@ -0,0 +1,776 @@
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;
using DevExpress.XtraGauges.Core.Model;
namespace LFP_Manager.Threads
{
#region DELEGATE
public delegate void UartDataUpdate(object sender, ref DeviceSystemData aSystemData);
public delegate void UartDataRecv(byte[] data);
public delegate void UartDataPrint(object sender, string msg);
#endregion
class csUartThread
{
#region VARIABLES
private readonly CommConfig Config;
private DeviceSystemData SystemData;
private Thread serialComm = null;
private SerialPort sPort = null;
private bool SerialPortThreadEnd = true;
public int SystemId = 0;
private bool UartPolling = false;
private bool AutoUartTx = true;
private int addr_ch = 0;
private ushort RequestRegAddr = 0x0000; //Byul Init 0x0000
private ushort RequestRegLen = 50;
private bool rFlag = false;
private int rFlag2 = 0;
private int wFlag = 0;
private ushort ReadRegAddr = 0x0000; //Byul Init 0x0000
private ushort ReadRegLen = 0x0000; //Byul Init 0x0000
private ushort WriteRegAddr = 0x0000; //Byul Init 0x0000
private short WriteCoilRegData = 0;
private byte[] WriteRegData;
private TUartTxBuff uartTxBuff = null;
public event UartDataUpdate OnUpdate = null;
public event UartDataRecv OnDataRecv = null;
public event UartDataPrint OnPrint = null;
#endregion
#region CONSTRUCTORS
public csUartThread(int sId, CommConfig aConfig, ref DeviceSystemData aSystemData)
{
SystemId = sId;
Config = aConfig;
SystemData = aSystemData;
uartTxBuff = new TUartTxBuff();
serialComm = new Thread(uartCommThread);
}
public void disposeThread()
{
if (sPort != null)
{
if (sPort.IsOpen)
{
sPort.Close();
}
sPort = null;
}
SerialPortThreadEnd = true;
if (serialComm != null)
{
if (serialComm.IsAlive)
{
serialComm.Abort();
}
serialComm = null;
}
}
public bool Start(ref CommConfig aConfig, int sId, bool aPolling)
{
bool result = false;
SystemId = sId;
UartPolling = aPolling;
if (Open(aConfig.UartPort, 115200)) //Byul Init 9600
{
SerialPortThreadEnd = false;
serialComm.Start();
result = true;
}
return result;
}
public void Stop()
{
SerialPortThreadEnd = true;
Close();
}
#endregion
#region COMMPORT CONTROLS
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);
for (int i = 0; i < rLen; i++)
{
PutBuff(sRead[i]);
}
}
catch (Exception)
{
}
}
private void sErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
{
//
//csMakeDataFunction.SetData()
}
private void sPinChanged(object sender, System.IO.Ports.SerialPinChangedEventArgs e)
{
//
}
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
{
sPort.Open();
}
catch (Exception ex)
{
throw new Exception("Error Open - " + ex.Message);
}
return sPort.IsOpen;
}
private void Close()
{
if (sPort != null)
{
if (sPort.IsOpen)
{
sPort.Close();
}
sPort = null;
}
}
#endregion
#region PUBLIC FUNCTION
public void SetPolling(bool flag, int sId, ref DeviceSystemData aSystemData)
{
SystemId = sId;
UartPolling = flag;
SystemData = aSystemData;
SystemData.mNo = SystemId;
}
public void SetAutoTx(bool 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)
{
WriteRegAddr = WriteAddr;
TUartTRxData uartTRxData = new TUartTRxData();
uartTRxData.type = type;
//uartTRxData.data = csSerialCommFunction.MakeWriteRegisterData((ushort)SystemId, WriteRegAddr, WriteData);
uartTRxData.data = WriteData;
uartTRxData.length = uartTRxData.data.Length;
uartTxBuff?.PutBuff(uartTRxData);
}
public void SetReadReg(ushort ReadAddr, ushort ReadLen, bool ReplyFlag)
{
wFlag = 4;
ReadRegAddr = ReadAddr;
ReadRegLen = ReadLen;
}
public void SetParam(ushort WriteAddr, short[] WriteData)
{
wFlag = 1;
WriteRegAddr = WriteAddr;
TUartTRxData uartTRxData = new TUartTRxData();
uartTRxData.type = wFlag;
uartTRxData.data = csSerialCommFunction.MakeWriteRegisterData((ushort)SystemId, WriteRegAddr, WriteData);
uartTRxData.length = uartTRxData.data.Length;
uartTxBuff?.PutBuff(uartTRxData);
}
public void SendProcessFromApp(int sId, int mode, int index, int flag, ref DeviceParamData aParam, ref DeviceCalibration aCalib)
{
short[] data = null;
switch (mode)
{
case csConstData.UART_PARAM_LIST.CELL_UNDER_VOLTAGE: // Cell Under Volatge Parameter
data = new short[1];
data[0] = aParam.CellUnderVoltageWarning; SetParam((ushort)(mode + 0), data);
data[0] = aParam.CellUnderVoltageTrip; SetParam((ushort)(mode + 1), data);
data[0] = aParam.CellUnderVoltageRelease; SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.CELL_OVER_VOLTAGE: // Cell Over Volatge Parameter
data = new short[1];
data[0] = aParam.CellOverVoltageWarning; SetParam((ushort)(mode + 0), data);
data[0] = aParam.CellOverVoltageTrip; SetParam((ushort)(mode + 1), data);
data[0] = aParam.CellOverVoltageRelease; SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.PACK_UNDER_VOLTAGE: // Pack Under Volatge Parameter
data = new short[1];
data[0] = (short)(aParam.SysUnderVoltageWarning * 10); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.SysUnderVoltageTrip * 10); SetParam((ushort)(mode + 1), data);
data[0] = (short)(aParam.SysUnderVoltageRelease * 10); SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.PACK_OVER_VOLTAGE: // Pack Over Volatge Parameter
data = new short[1];
data[0] = (short)(aParam.SysOverVoltageWarning * 10); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.SysOverVoltageTrip * 10); SetParam((ushort)(mode + 1), data);
data[0] = (short)(aParam.SysOverVoltageRelease * 10); SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.CHG_LOW_TEMPERATURE: // Charge Low Temperature Parameter
data = new short[1];
data[0] = (short)(aParam.ChaLowTempWarning + 50); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.ChaLowTempTrip + 50); SetParam((ushort)(mode + 1), data);
data[0] = (short)(aParam.ChaLowTempRelease + 50); SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.CHG_HIGH_TEMPERATURE: // Pack High Temperature Parameter
data = new short[1];
data[0] = (short)(aParam.ChaHighTempWarning + 50); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.ChaHighTempTrip + 50); SetParam((ushort)(mode + 1), data);
data[0] = (short)(aParam.ChaHighTempRelease + 50); SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.DCH_LOW_TEMPERATURE: // Charge Low Temperature Parameter
data = new short[1];
data[0] = (short)(aParam.DchLowTempWarning + 50); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.DchLowTempTrip + 50); SetParam((ushort)(mode + 1), data);
data[0] = (short)(aParam.DchLowTempRelease + 50); SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.DCH_HIGH_TEMPERATURE: // Pack High Temperature Parameter
data = new short[1];
data[0] = (short)(aParam.DchHighTempWarning + 50); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.DchHighTempTrip + 50); SetParam((ushort)(mode + 1), data);
data[0] = (short)(aParam.DchHighTempRelease + 50); SetParam((ushort)(mode + 2), data);
break;
case csConstData.UART_PARAM_LIST.CHG_OVER_CURRENT: // Charge Over Current Parameter
data = new short[1];
data[0] = (short)(aParam.ChaOverCurrentReleaseTime * 1); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.ChaOverCurrentTrip1 * 10); SetParam((ushort)(mode + 2), data);
data[0] = (short)(aParam.ChaOverCurrentTrip2 * 10); SetParam((ushort)(mode + 5), data);
break;
case csConstData.UART_PARAM_LIST.DCH_OVER_CURRENT: // Discharge Over Current Parameter
data = new short[1];
data[0] = (short)(aParam.DchOverCurrentReleaseTime * 1); SetParam((ushort)(mode + 0), data);
data[0] = (short)(aParam.DchOverCurrentTrip1 * 10); SetParam((ushort)(mode + 2), data);
data[0] = (short)(aParam.DchOverCurrentTrip2 * 10); SetParam((ushort)(mode + 5), data);
break;
case csConstData.UART_PARAM_LIST.LOW_CAPACITY:
data = new short[1];
data[0] = aParam.LowSocWarning; SetParam((ushort)(mode + 0), data);
break;
case csConstData.UART_PARAM_LIST.DEFAULT_PARAM: // Default Parameter
int i = 0;
Forms.fmxWait WaitForm = new Forms.fmxWait();
WaitForm.StartPosition = FormStartPosition.CenterScreen;
try
{
//WaitForm.Show();
data = new short[1];
i = csConstData.UART_PARAM_LIST.CELL_UNDER_VOLTAGE;
data[0] = csConstData.UART_PARAM_DEFAULT.Warn_Cell_UV; SetParam((ushort)(i + 0), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Protect_Cell_UV; SetParam((ushort)(i + 1), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Release_Cell_UV; SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.PACK_UNDER_VOLTAGE;
data[0] = csConstData.UART_PARAM_DEFAULT.Warn_Pack_UV; SetParam((ushort)(i + 0), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Protect_Pack_UV; SetParam((ushort)(i + 1), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Release_Pack_UV; SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.CELL_OVER_VOLTAGE;
data[0] = csConstData.UART_PARAM_DEFAULT.Warn_Cell_OV; SetParam((ushort)(i + 0), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Protect_Cell_OV; SetParam((ushort)(i + 1), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Release_Cell_OV; SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.PACK_OVER_VOLTAGE;
data[0] = csConstData.UART_PARAM_DEFAULT.Warn_Pack_OV; SetParam((ushort)(i + 0), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Protect_Pack_OV; SetParam((ushort)(i + 1), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Release_Pack_OV; SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.CHG_OVER_CURRENT;
data[0] = csConstData.UART_PARAM_DEFAULT.Times_Charge_OC; SetParam((ushort)(i - 2), data);
data[0] = csConstData.UART_PARAM_DEFAULT.ReleaseTime_Charge_OC; SetParam((ushort)(i + 0), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Protect_Charge_OC1; SetParam((ushort)(i + 2), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Protect_Charge_OC2; SetParam((ushort)(i + 5), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Delay_Charge_OC1; SetParam((ushort)(i + 8), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Delay_Charge_OC2; SetParam((ushort)(i + 9), data);
i = csConstData.UART_PARAM_LIST.DCH_OVER_CURRENT;
data[0] = csConstData.UART_PARAM_DEFAULT.Times_Discharge_OC; SetParam((ushort)(i - 2), data);
data[0] = csConstData.UART_PARAM_DEFAULT.ReleaseTime_Discharge_OC; SetParam((ushort)(i + 0), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Protect_Discharge_OC1; SetParam((ushort)(i + 2), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Protect_Discharge_OC2; SetParam((ushort)(i + 5), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Delay_Discharge_OC1; SetParam((ushort)(i + 8), data);
data[0] = csConstData.UART_PARAM_DEFAULT.Delay_Discharge_OC2; SetParam((ushort)(i + 9), data);
i = csConstData.UART_PARAM_LIST.CHG_LOW_TEMPERATURE;
data[0] = (short)(csConstData.UART_PARAM_DEFAULT.Warn_Charge_UT + 50); SetParam((ushort)(i + 0), data);
data[0] = (short)(csConstData.UART_PARAM_DEFAULT.Protect_Charge_UT + 50); SetParam((ushort)(i + 1), data);
data[0] = (short)(csConstData.UART_PARAM_DEFAULT.Release_Charge_UT + 50); SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.CHG_HIGH_TEMPERATURE;
data[0] = (short)(csConstData.UART_PARAM_DEFAULT.Warn_Charge_OT + 50); SetParam((ushort)(i + 0), data);
data[0] = (short)(csConstData.UART_PARAM_DEFAULT.Protect_Charge_OT + 50); SetParam((ushort)(i + 1), data);
data[0] = (short)(csConstData.UART_PARAM_DEFAULT.Release_Charge_OT + 50); SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.DCH_LOW_TEMPERATURE;
data[0] = (short)(csConstData.UART_PARAM_DEFAULT.Warn_Discharge_UT + 50); SetParam((ushort)(i + 0), data);
data[0] = (short)(csConstData.UART_PARAM_DEFAULT.Protect_Discharge_UT + 50); SetParam((ushort)(i + 1), data);
data[0] = (short)(csConstData.UART_PARAM_DEFAULT.Release_Discharge_UT + 50); SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.DCH_HIGH_TEMPERATURE;
data[0] = (short)(csConstData.UART_PARAM_DEFAULT.Warn_Discharge_OT + 50); SetParam((ushort)(i + 0), data);
data[0] = (short)(csConstData.UART_PARAM_DEFAULT.Protect_Discharge_OT + 50); SetParam((ushort)(i + 1), data);
data[0] = (short)(csConstData.UART_PARAM_DEFAULT.Release_Discharge_OT + 50); SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.LOW_CAPACITY;
data[0] = csConstData.UART_PARAM_DEFAULT.Warn_Low_Capacity + 0; SetParam((ushort)(i + 0), data);
i = csConstData.UART_PARAM_LIST.ENV_LOW_TEMPERATURE;
data[0] = 0; SetParam((ushort)(i + 0), data);
data[0] = 0; SetParam((ushort)(i + 1), data);
data[0] = 0; SetParam((ushort)(i + 2), data);
i = csConstData.UART_PARAM_LIST.ENV_HIGH_TEMPERATURE;
data[0] = 0; SetParam((ushort)(i + 0), data);
data[0] = 0; SetParam((ushort)(i + 1), data);
data[0] = 0; SetParam((ushort)(i + 2), data);
}
catch (Exception)
{
}
finally
{
//WaitForm?.Close();
}
break;
case 15: // Capcity change
data = new short[1];
i = csConstData.UART_PARAM_LIST.DESIGN_CAPACITY;
data[0] = (short)aCalib.CapCalib.DesignCapacity; SetParam((ushort)(i + 0), data);
i = csConstData.UART_PARAM_LIST.SOC_VALUE;
data[0] = (short)aCalib.CapCalib.SocValue; SetParam((ushort)(i + 0), data);
break;
case 16: // Charge Mode
data = new short[1];
i = csConstData.UART_CALIB_ADDR_LIST.CHAGE_MODE;
data[0] = (short)aCalib.ChaMode.Mode; SetParam((ushort)(i + 0), data);
data[0] = (short)aCalib.ChaMode.Value; SetParam((ushort)(i + 1), data);
break;
case 17: // BMS DateTime Set
data = new short[2];
i = csConstData.UART_CALIB_ADDR_LIST.BMS_DATETIME;
data[0] = (short)aCalib.BmsDateTime.sValue[0];
data[1] = (short)aCalib.BmsDateTime.sValue[1]; SetParam((ushort)(i + 0), data);
break;
case 18:
data = new short[1];
i = csConstData.UART_CALIB_ADDR_LIST.ANTI_THEFT_GYRO;
data[0] = (short)aCalib.AntiTheft.GyroScope; SetParam((ushort)(i + 0), data);
break;
case 19: // Clear Protect
data = new short[1];
i = csConstData.UART_CALIB_ADDR_LIST.ANTI_THEFT_GYRO;
data[0] = (short)0; SetParam((ushort)(i + 0), data);
data[0] = (short)aCalib.AntiTheft.GyroScope; SetParam((ushort)(i + 0), data);
break;
case 20:
data = new short[1];
i = csConstData.UART_CALIB_ADDR_LIST.ANTI_THEFT_COMM;
data[0] = (short)aCalib.AntiTheft.Comm; SetParam((ushort)(i + 0), data);
break;
case 21: // Cell Balancing Voltage
data = new short[1];
i = csConstData.UART_CALIB_ADDR_LIST.BAL_VOLT;
data[0] = (short)aCalib.BalCalib.Volt; SetParam((ushort)(i + 0), data);
break;
case 22: // Cell Balancing Diff
data = new short[1];
i = csConstData.UART_CALIB_ADDR_LIST.BAL_DIFF;
data[0] = (short)aCalib.BalCalib.Volt; SetParam((ushort)(i + 0), data);
break;
default:
break;
}
}
#endregion
#region RX BUFFERING
private const int BUFFER_SIZE = 512;
private readonly byte[] rBuffer = new byte[BUFFER_SIZE];
private int rBufStart = 0;
private int rBufEnd = 0;
private void PutBuff(byte c)
{
rBuffer[rBufStart++] = c;
rBufStart %= BUFFER_SIZE;
if (rBufStart == rBufEnd)
{
rBufEnd++;
rBufEnd %= BUFFER_SIZE;
}
}
private int GetBuff()
{
int result = 0;
if (rBufStart != rBufEnd)
{
result = 0x0100 + rBuffer[rBufEnd++];
rBufEnd %= BUFFER_SIZE;
}
return result;
}
private void FlushBuff()
{
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[] MakeTxDataVision(ref bool wData)
{
byte[] sData = null;
rFlag2 = 0;
if ((uartTxBuff != null) && (uartTxBuff.CheckBuff()))
{
TUartTRxData sBuff = uartTxBuff.GetBuff();
if (sBuff != null)
{
sData = sBuff.data;
wData = true;
rFlag = true;
rFlag2 = sBuff.type;
}
}
else if (wFlag == 2)
{
sData = csSerialCommFunction.MakeWriteCoilData((ushort)SystemId, WriteRegAddr, WriteCoilRegData);
if (wFlag != 0) wFlag = 0;
rFlag = true;
}
else if (wFlag == 3)
{
sData = WriteRegData;
if (wFlag != 0) wFlag = 0;
rFlag = true;
}
else if (wFlag == 4)
{
sData = csSerialCommFunction.MakeReadRegisterData((ushort)SystemId, csSerialCommFunction.READ_HOLDING_REG, ReadRegAddr, ReadRegLen);
if (wFlag != 0) wFlag = 0;
rFlag = true;
}
else
{
if (UartPolling && AutoUartTx)
{
ushort sCmd;
switch (addr_ch)
{
case 0:
addr_ch = 1;
RequestRegAddr = 0x0000; //Byul Init 0x0000
RequestRegLen = 0x0040;
sCmd = csSerialCommFunction.READ_HOLDING_REG;
rFlag = true;
break;
case 1:
addr_ch = 2;
RequestRegAddr = 0x0040;
RequestRegLen = 0x0040;
sCmd = csSerialCommFunction.READ_HOLDING_REG;
rFlag = true;
break;
case 2:
addr_ch = 3;
RequestRegAddr = 0x0080;
RequestRegLen = 0x0020 + 7;
sCmd = csSerialCommFunction.READ_HOLDING_REG;
rFlag = true;
break;
case 3:
if (Config.ModuleQty > 1)
{
SystemId++;
if (SystemId > Config.ModuleQty)
{
SystemId = 1;
}
}
addr_ch = 0;
sCmd = csSerialCommFunction.NO_CMD;
rFlag = false;
break;
default:
addr_ch = 0;
RequestRegAddr = 0x0000; //Byul Init 0x0000
RequestRegLen = 100;
sCmd = csSerialCommFunction.READ_HOLDING_REG;
break;
}
if (sCmd == csSerialCommFunction.NO_CMD)
{
sData = null;
}
else
{
sData = csSerialCommFunction.MakeReadRegisterData((ushort)SystemId, sCmd, RequestRegAddr, RequestRegLen);
}
}
}
return sData;
}
#endregion
#region COMM THREAD
private readonly byte[] ReadBuf = new byte[BUFFER_SIZE];
ushort rPosition = 0;
bool BuffStart = false;
private void RecvPacketInit()
{
BuffStart = false;
rPosition = 0;
}
private void uartCommThread()
{
int RecvTimeout = Config.RecvWaitTime;
int getData = 0;
byte cData = 0;
int TimeOutCount = 0;
StartSend:
while (SerialPortThreadEnd == false)
{
if ((sPort == null) || (sPort.IsOpen == false)) continue;
bool wMode = false;
byte[] txData = MakeTxDataVision(ref wMode);
if (txData != null)
{
FlushBuff();
sPort.Write(txData, 0, txData.Length);
OnPrint?.Invoke(this, csLog.trx_data_print(txData, txData.Length, 0));
}
if (rFlag == true)
{
RecvPacketInit();
DateTime rDateTime = DateTime.Now;
while (true)
{
DateTime nDateTime = rDateTime.AddMilliseconds(RecvTimeout);
if (nDateTime < DateTime.Now) break;
if (((getData = GetBuff()) & 0x0100) != 0x0000)
{
rDateTime = DateTime.Now;
cData = (byte)(getData & 0x00FF);
if (rPosition >= BUFFER_SIZE) RecvPacketInit();
if (BuffStart == false)
{
if ((cData == (byte)SystemId) || (cData == (byte)0x7F))
{
rPosition = 0;
ReadBuf[rPosition++] = cData;
BuffStart = true;
}
}
else
{
ReadBuf[rPosition++] = cData;
switch (csSerialCommFunction.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 = 0;
int mID = ReadBuf[0];
if (mID > 0) mID--;
SystemData.CommFail = false;
SystemData.ShelfCommFail = false;
if (rFlag2 == 0)
{
short[] result_code = csSerialCommFunction.SerialRxProcess(ReadBuf, RequestRegAddr, rPosition, ref SystemData);
OnUpdate?.Invoke(this, ref SystemData);
}
else
{
rFlag2 = 0;
wMode = false;
WriteRegAddr = 0;
if (OnDataRecv != null)
{
byte[] adata = new byte[rPosition + 1];
for (int j = 0; j < adata.Length; j++) { adata[j] = ReadBuf[j]; }
OnDataRecv(adata);
}
}
rFlag = false;
Thread.Sleep(100);
goto StartSend;
case 2: // Fw Update Packet OK
OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1));
TimeOutCount = 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;
}
}
}
else
{
Thread.Sleep(1);
}
}
if (rPosition > 0)
{
Thread.Sleep(1);
}
else
{
WriteRegAddr = 0;
TimeOutCount++;
if (TimeOutCount >= 5)
{
TimeOutCount = 5;
//SystemData[0].CommFail = true;
if (SystemData.ShelfCommFail == false)
{
SystemData.ShelfCommFail = true;
csUtils.DataInit(Config, ref SystemData);
}
}
Thread.Sleep(100);
}
OnUpdate?.Invoke(this, ref SystemData);
Thread.Sleep(1);
}
else
{
Thread.Sleep(100);
} /* if (rFlag == true) */
rPosition = 0;
}
}
#endregion
}
}