초기 커밋.
This commit is contained in:
552
LFP_Manager/Threads/CsDbAsyncTask.cs
Normal file
552
LFP_Manager/Threads/CsDbAsyncTask.cs
Normal 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
|
||||
}
|
||||
}
|
||||
706
LFP_Manager/Threads/CsRs232Thread124050.cs
Normal file
706
LFP_Manager/Threads/CsRs232Thread124050.cs
Normal 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
|
||||
}
|
||||
}
|
||||
568
LFP_Manager/Threads/CsRs485Thread124050.cs
Normal file
568
LFP_Manager/Threads/CsRs485Thread124050.cs
Normal 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
|
||||
}
|
||||
}
|
||||
526
LFP_Manager/Threads/CsSnmpThread.cs
Normal file
526
LFP_Manager/Threads/CsSnmpThread.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
583
LFP_Manager/Threads/CsSnmpThread124050.cs
Normal file
583
LFP_Manager/Threads/CsSnmpThread124050.cs
Normal 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
|
||||
}
|
||||
}
|
||||
765
LFP_Manager/Threads/CsUartThread124050.cs
Normal file
765
LFP_Manager/Threads/CsUartThread124050.cs
Normal 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
|
||||
}
|
||||
}
|
||||
574
LFP_Manager/Threads/CsUartThreadDelta.cs
Normal file
574
LFP_Manager/Threads/CsUartThreadDelta.cs
Normal 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
|
||||
}
|
||||
}
|
||||
315
LFP_Manager/Threads/csDbThread.cs
Normal file
315
LFP_Manager/Threads/csDbThread.cs
Normal 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
|
||||
}
|
||||
}
|
||||
776
LFP_Manager/Threads/csUartThread.cs
Normal file
776
LFP_Manager/Threads/csUartThread.cs
Normal 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user