using GSModbus.Config;
using GSModbus.Database;
namespace GSModbus
{
///
/// 通用MES系统主窗体 - 基于配置的Modbus通信界面
///
public partial class Form1 : Form
{
#region 私有字段
///
/// 配置管理器
///
private ConfigurationManager? _configManager;
///
/// 通用Modbus通信管理器实例
///
private UniversalModbusManager? _universalModbusManager;
///
/// 数据接收计数器
///
private int _dataReceiveCount = 0;
#endregion
#region 构造函数
///
/// 初始化主窗体
///
public Form1()
{
InitializeComponent();
InitializeConfigManager();
SetupEventHandlers();
UpdateConnectionStatus(false);
// 初始化数据库状态
lblDatabaseStatus.Text = "未检测";
lblDatabaseStatus.ForeColor = Color.Gray;
btnTestDatabase.Enabled = false;
// 尝试加载默认配置
LoadDefaultConfigurationAsync();
}
#endregion
#region 初始化方法
///
/// 初始化配置管理器
///
private void InitializeConfigManager()
{
try
{
_configManager = new ConfigurationManager();
// 订阅配置管理器的事件
_configManager.ConfigurationLoaded += OnConfigurationLoaded;
_configManager.ConfigurationError += OnConfigurationError;
LogMessage("配置管理器初始化完成");
}
catch (Exception ex)
{
LogMessage($"初始化配置管理器失败: {ex.Message}");
MessageBox.Show($"初始化失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
///
/// 设置控件事件处理程序
///
private void SetupEventHandlers()
{
// 窗体关闭事件
this.FormClosing += Form1_FormClosing;
// 按钮事件
btnLoadConfig.Click += BtnLoadConfig_Click;
btnConnect.Click += BtnConnect_Click;
btnDisconnect.Click += BtnDisconnect_Click;
btnClearLog.Click += BtnClearLog_Click;
btnTestDatabase.Click += BtnTestDatabase_Click;
}
#endregion
#region 配置管理方法
///
/// 加载默认配置
///
private async void LoadDefaultConfigurationAsync()
{
if (_configManager == null) return;
try
{
LogMessage("正在尝试加载默认配置文件...");
var loaded = await _configManager.LoadDefaultConfigurationAsync();
if (!loaded)
{
LogMessage("默认配置文件不存在,请手动选择配置文件");
lblConfigPath.Text = "未加载配置文件";
lblConfigPath.ForeColor = Color.Red;
}
}
catch (Exception ex)
{
LogMessage($"加载默认配置失败: {ex.Message}");
}
}
///
/// 配置加载成功事件处理
///
private void OnConfigurationLoaded(object? sender, ConfigurationLoadedEventArgs e)
{
// 确保在UI线程中执行
if (InvokeRequired)
{
Invoke(new Action(() => OnConfigurationLoaded(sender, e)));
return;
}
try
{
// 更新配置显示
var fileName = Path.GetFileName(e.ConfigPath);
lblConfigPath.Text = fileName;
lblConfigPath.ForeColor = Color.Green;
// 更新窗体标题
this.Text = $"GSModbus - {e.Configuration.ProjectName}";
// 如果有现有的连接,先断开
if (_universalModbusManager?.IsConnected == true)
{
_universalModbusManager.Disconnect();
}
// 释放现有的管理器
_universalModbusManager?.Dispose();
// 创建新的通用Modbus管理器
_universalModbusManager = new UniversalModbusManager(e.Configuration);
SetupModbusManagerEvents();
LogMessage($"✅ 配置加载成功: {e.Configuration.ProjectName}");
LogMessage($" PLC地址: {e.Configuration.Connection.IpAddress}:{e.Configuration.Connection.Port}");
LogMessage($" 数据字段: {GetTotalFieldCount(e.Configuration)} 个");
// 更新数据库状态
UpdateDatabaseStatus(e.Configuration.Database);
// 启用连接按钮
btnConnect.Enabled = true;
}
catch (Exception ex)
{
LogMessage($"处理配置加载事件时发生错误: {ex.Message}");
}
}
///
/// 配置错误事件处理
///
private void OnConfigurationError(object? sender, ConfigurationErrorEventArgs e)
{
// 确保在UI线程中执行
if (InvokeRequired)
{
Invoke(new Action(() => OnConfigurationError(sender, e)));
return;
}
lblConfigPath.Text = "配置文件错误";
lblConfigPath.ForeColor = Color.Red;
btnConnect.Enabled = false;
// 重置数据库状态
lblDatabaseStatus.Text = "未检测";
lblDatabaseStatus.ForeColor = Color.Gray;
btnTestDatabase.Enabled = false;
LogMessage($"❌ 配置错误: {e.ErrorMessage}");
}
///
/// 设置Modbus管理器事件
///
private void SetupModbusManagerEvents()
{
if (_universalModbusManager == null) return;
_universalModbusManager.ConnectionStatusChanged += OnConnectionStatusChanged;
_universalModbusManager.DataReceived += OnDataReceived;
_universalModbusManager.ErrorOccurred += OnErrorOccurred;
_universalModbusManager.StatsUpdated += OnStatsUpdated;
_universalModbusManager.DatabaseLogOccurred += OnDatabaseLogOccurred;
_universalModbusManager.DatabaseErrorOccurred += OnDatabaseErrorOccurred;
}
#endregion
#region 事件处理方法
///
/// 选择配置文件按钮点击事件
///
private async void BtnLoadConfig_Click(object? sender, EventArgs e)
{
try
{
var openFileDialog = new OpenFileDialog
{
Title = "选择Modbus配置文件",
Filter = "JSON配置文件 (*.json)|*.json|所有文件 (*.*)|*.*",
InitialDirectory = Path.Combine(Application.StartupPath, "config"),
RestoreDirectory = true
};
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
LogMessage($"正在加载配置文件: {openFileDialog.FileName}");
if (_configManager != null)
{
await _configManager.LoadConfigurationAsync(openFileDialog.FileName);
}
}
}
catch (Exception ex)
{
LogMessage($"选择配置文件时发生错误: {ex.Message}");
MessageBox.Show($"加载配置文件失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
///
/// 连接按钮点击事件
///
private async void BtnConnect_Click(object? sender, EventArgs e)
{
if (_universalModbusManager == null)
{
LogMessage("❌ 请先加载配置文件");
MessageBox.Show("请先选择并加载配置文件", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
btnConnect.Enabled = false;
btnConnect.Text = "连接中...";
LogMessage("🔗 正在连接到PLC...");
bool connected = await _universalModbusManager.ConnectAsync();
if (!connected)
{
LogMessage("❌ 连接PLC失败");
MessageBox.Show("无法连接到PLC,请检查网络连接和PLC状态", "连接失败",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
catch (Exception ex)
{
LogMessage($"❌ 连接过程中发生错误: {ex.Message}");
MessageBox.Show($"连接错误: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
btnConnect.Text = "连接PLC";
btnConnect.Enabled = !(_universalModbusManager?.IsConnected ?? false);
}
}
///
/// 断开连接按钮点击事件
///
private void BtnDisconnect_Click(object? sender, EventArgs e)
{
try
{
LogMessage("🔌 正在断开PLC连接...");
_universalModbusManager?.Disconnect();
}
catch (Exception ex)
{
LogMessage($"❌ 断开连接时发生错误: {ex.Message}");
}
}
///
/// 清除日志按钮点击事件
///
private void BtnClearLog_Click(object? sender, EventArgs e)
{
txtLog.Clear();
_dataReceiveCount = 0;
lblDataCount.Text = "数据接收次数: 0";
}
///
/// 数据库测试按钮点击事件
///
private async void BtnTestDatabase_Click(object? sender, EventArgs e)
{
if (_configManager?.CurrentConfiguration?.Database == null)
{
LogMessage("❌ 请先加载包含数据库配置的配置文件");
MessageBox.Show("请先选择并加载包含数据库配置的配置文件", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
btnTestDatabase.Enabled = false;
btnTestDatabase.Text = "测试中...";
lblDatabaseStatus.Text = "测试中...";
lblDatabaseStatus.ForeColor = Color.Orange;
LogMessage("🔍 正在测试数据库连接...");
var dbConfig = _configManager.CurrentConfiguration.Database;
var (success, message) = await DatabaseManager.TestConnectionAsync(dbConfig);
if (success)
{
lblDatabaseStatus.Text = "连接成功";
lblDatabaseStatus.ForeColor = Color.Green;
LogMessage($"✅ 数据库连接测试成功");
LogMessage($" {message}");
}
else
{
lblDatabaseStatus.Text = "连接失败";
lblDatabaseStatus.ForeColor = Color.Red;
LogMessage($"❌ 数据库连接测试失败: {message}");
}
}
catch (Exception ex)
{
lblDatabaseStatus.Text = "测试异常";
lblDatabaseStatus.ForeColor = Color.Red;
LogMessage($"❌ 数据库连接测试异常: {ex.Message}");
MessageBox.Show($"数据库连接测试异常: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
btnTestDatabase.Text = "测试数据库";
btnTestDatabase.Enabled = true;
}
}
///
/// 窗体关闭事件 - 清理资源
///
private void Form1_FormClosing(object? sender, FormClosingEventArgs e)
{
try
{
LogMessage("正在关闭应用程序...");
_universalModbusManager?.Dispose();
}
catch (Exception ex)
{
// 关闭时的错误不需要显示给用户
System.Diagnostics.Debug.WriteLine($"关闭时发生错误: {ex.Message}");
}
}
#endregion
#region Modbus事件处理
///
/// Modbus连接状态改变事件处理
///
private void OnConnectionStatusChanged(object? sender, bool isConnected)
{
// 由于此事件可能在非UI线程中触发,需要使用Invoke来更新UI
if (InvokeRequired)
{
Invoke(new Action(() => UpdateConnectionStatus(isConnected)));
}
else
{
UpdateConnectionStatus(isConnected);
}
}
///
/// 接收到动态数据事件处理 - 通过日志显示
///
private void OnDataReceived(object? sender, DynamicModbusData data)
{
// 由于此事件可能在非UI线程中触发,需要使用Invoke来更新UI
if (InvokeRequired)
{
Invoke(new Action(() => DisplayDataInLog(data)));
}
else
{
DisplayDataInLog(data);
}
}
///
/// Modbus错误发生事件处理
///
private void OnErrorOccurred(object? sender, string errorMessage)
{
// 由于此事件可能在非UI线程中触发,需要使用Invoke来更新UI
if (InvokeRequired)
{
Invoke(new Action(() => LogMessage($"⚠️ 通信错误: {errorMessage}")));
}
else
{
LogMessage($"⚠️ 通信错误: {errorMessage}");
}
}
///
/// 统计信息更新事件处理
///
private void OnStatsUpdated(object? sender, CommunicationStats stats)
{
// 由于此事件可能在非UI线程中触发,需要使用Invoke来更新UI
if (InvokeRequired)
{
Invoke(new Action(() => UpdateStatsDisplay(stats)));
}
else
{
UpdateStatsDisplay(stats);
}
}
///
/// 数据库日志事件处理
///
private void OnDatabaseLogOccurred(object? sender, string logMessage)
{
// 由于此事件可能在非UI线程中触发,需要使用Invoke来更新UI
if (InvokeRequired)
{
Invoke(new Action(() => LogMessage(logMessage)));
}
else
{
LogMessage(logMessage);
}
}
///
/// 数据库错误事件处理
///
private void OnDatabaseErrorOccurred(object? sender, string errorMessage)
{
// 由于此事件可能在非UI线程中触发,需要使用Invoke来更新UI
if (InvokeRequired)
{
Invoke(new Action(() => LogMessage($"⚠️ {errorMessage}")));
}
else
{
LogMessage($"⚠️ {errorMessage}");
}
}
#endregion
#region UI更新方法
///
/// 更新连接状态显示
///
/// 是否已连接
private void UpdateConnectionStatus(bool isConnected)
{
if (isConnected)
{
lblConnectionStatus.Text = "已连接";
lblConnectionStatus.ForeColor = Color.Green;
btnConnect.Enabled = false;
btnDisconnect.Enabled = true;
LogMessage("✅ 成功连接到PLC,开始数据通信");
}
else
{
lblConnectionStatus.Text = "未连接";
lblConnectionStatus.ForeColor = Color.Red;
btnConnect.Enabled = _configManager?.IsConfigurationLoaded ?? false;
btnDisconnect.Enabled = false;
// 重置计数
_dataReceiveCount = 0;
lblDataCount.Text = "数据接收次数: 0";
}
}
///
/// 在日志中显示动态数据
///
/// 动态数据
private void DisplayDataInLog(DynamicModbusData data)
{
if (data == null) return;
try
{
_dataReceiveCount++;
lblDataCount.Text = $"数据接收次数: {_dataReceiveCount}";
// 构建数据日志条目
var logEntry = new List
{
$"📊 [数据 #{_dataReceiveCount}] {data.ReadTime:HH:mm:ss.fff}"
};
// 按类别显示数据
var allFields = GetAllFieldsByCategory(data);
foreach (var category in allFields)
{
if (category.Value.Any())
{
logEntry.Add($" {category.Key}:");
foreach (var field in category.Value)
{
var config = data.GetFieldConfiguration(field.Key);
var displayValue = config != null ?
ModbusDataParser.FormatDisplayValue(field.Value, config) :
field.Value?.ToString() ?? "null";
logEntry.Add($" • {config?.DisplayName ?? field.Key}: {displayValue}");
}
}
}
// 添加分隔线
logEntry.Add(" " + new string('-', 50));
// 批量添加到日志
foreach (var line in logEntry)
{
AppendLogMessage(line);
}
}
catch (Exception ex)
{
LogMessage($"❌ 显示数据时发生错误: {ex.Message}");
}
}
///
/// 更新统计信息显示
///
/// 统计信息
private void UpdateStatsDisplay(CommunicationStats stats)
{
lblStats.Text = stats.GetSummary();
}
///
/// 更新数据库状态显示
///
/// 数据库配置
private void UpdateDatabaseStatus(DatabaseConfig? dbConfig)
{
if (dbConfig == null)
{
lblDatabaseStatus.Text = "未配置";
lblDatabaseStatus.ForeColor = Color.Gray;
btnTestDatabase.Enabled = false;
LogMessage(" 数据库: 未配置");
}
else if (!dbConfig.Enabled)
{
lblDatabaseStatus.Text = "已禁用";
lblDatabaseStatus.ForeColor = Color.Gray;
btnTestDatabase.Enabled = false;
LogMessage(" 数据库: 已禁用");
}
else
{
lblDatabaseStatus.Text = "未检测";
lblDatabaseStatus.ForeColor = Color.Orange;
btnTestDatabase.Enabled = true;
LogMessage($" 数据库: {dbConfig.Type} - 已配置,可测试连接");
}
}
#endregion
#region 辅助方法
///
/// 按类别获取所有字段数据
///
private Dictionary> GetAllFieldsByCategory(DynamicModbusData data)
{
var result = new Dictionary>
{
["控制信号"] = new Dictionary(),
["产品数据"] = new Dictionary(),
["测量数据"] = new Dictionary()
};
if (data.SourceConfiguration?.InputAddresses == null)
return result;
// 控制信号
foreach (var field in data.SourceConfiguration.InputAddresses.ControlSignals)
{
if (data.HasField(field.Key))
{
result["控制信号"][field.Key] = data.GetFieldValue(field.Key);
}
}
// 产品数据
foreach (var field in data.SourceConfiguration.InputAddresses.ProductData)
{
if (data.HasField(field.Key))
{
result["产品数据"][field.Key] = data.GetFieldValue(field.Key);
}
}
// 测量数据
foreach (var field in data.SourceConfiguration.InputAddresses.MeasurementData)
{
if (data.HasField(field.Key))
{
result["测量数据"][field.Key] = data.GetFieldValue(field.Key);
}
}
return result;
}
///
/// 获取配置中的总字段数
///
private int GetTotalFieldCount(ModbusConfiguration config)
{
return config.InputAddresses.ControlSignals.Count +
config.InputAddresses.ProductData.Count +
config.InputAddresses.MeasurementData.Count;
}
///
/// 记录日志消息
///
/// 日志消息
private void LogMessage(string message)
{
string logEntry = $"[{DateTime.Now:HH:mm:ss}] {message}";
if (txtLog.InvokeRequired)
{
txtLog.Invoke(new Action(() => AppendLogMessage(logEntry)));
}
else
{
AppendLogMessage(logEntry);
}
}
///
/// 添加日志消息到文本框
///
private void AppendLogMessage(string logEntry)
{
txtLog.AppendText(logEntry + Environment.NewLine);
txtLog.SelectionStart = txtLog.Text.Length;
txtLog.ScrollToCaret();
// 限制日志行数,避免内存占用过大
var lines = txtLog.Lines;
if (lines.Length > 2000)
{
var newLines = lines.Skip(200).ToArray();
txtLog.Text = string.Join(Environment.NewLine, newLines);
}
}
#endregion
}
}