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