using Modbus.Device; using Sunny.UI; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using 全自动水压检测仪; using 全自动水压检测仪.Data; using 全自动水压检测仪.DATA; namespace 全自动水压检测仪 { public partial class Coeffiicientsetting : UIForm { private NormalTemperatureMode _normalTemperatureMode; private TcpClient _tcpClient => ModbusResourceManager.Instance.TcpClient; private IModbusMaster _modbusMaster => ModbusResourceManager.Instance.ModbusMaster; Function ma; DataChange c; private System.Windows.Forms.Timer _readTimer; private bool _isManualInput = false; // 手动输入标记 private bool _isSwitchingWindow = false; // 窗口切换标记,避免并发 private CancellationTokenSource _cts; // 取消令牌,用于异步操作终止 public Coeffiicientsetting() { InitializeComponent(); _cts = new CancellationTokenSource(); // 只创建定时器,不在构造器中启动,避免在 Load 前访问未初始化的资源(如 c / _modbusMaster) _readTimer = InitTimer(); // 初始化定时器并保存引用 } private System.Windows.Forms.Timer InitTimer() { var timer = new System.Windows.Forms.Timer() { Interval = 1000 }; timer.Tick += async (s, e) => { if (!_isManualInput && _modbusMaster != null) { try { await ReadLeakTestParametersAsync(); } catch { } } }; // 不在此处 Start,等待 Load 完成后再 Start() return timer; } private class RegisterConfig { public ushort Address { get; set; } // Modbus寄存器地址(ushort类型匹配方法参数) public UITextBox TextBox { get; set; } // 适配SunnyUI的UITextBox控件 public string Format { get; set; } // 数值格式化字符串 public bool IsInteger { get; set; } // 是否为整数类型(新增) } private async Task ReadLeakTestParametersAsync() { // 前置校验:连接状态检查 if (_tcpClient == null || !_tcpClient.Connected || _modbusMaster == null) return; // 确保 UI 已可用 if (!this.IsHandleCreated || this.IsDisposed) return; try { var registerConfigs = new List { CreateRegisterConfig(2394, uiTextBox1, "F2",false), // 控制压力系数 CreateRegisterConfig(3134, uiTextBox3, "F2",false), // 压力保护输入 //CreateRegisterConfig(2376, uiTextBox2, "F2",false), // 压力上限 //CreateRegisterConfig(2374, uiTextBox4, "F2",false), // 压力下限 CreateRegisterConfig(3482, uiTextBox8, "F2",false), // 温度系数 CreateRegisterConfig(3176, uiTextBox6, "F2",false), // 出口温度系数 CreateRegisterConfig(3076, uiTextBox7, "F2",false), // 常温液位系数 CreateRegisterConfig(3086, uiTextBox9, "F2",false), // 常温液位上限 CreateRegisterConfig(3084, uiTextBox10, "F2",false), // 常温液位下限 CreateRegisterConfig(3026, uiTextBox12, "F2",false), // 高温液位系数 CreateRegisterConfig(3036, uiTextBox11, "F2",false), // 高温液位上限 CreateRegisterConfig(3034, uiTextBox5, "F2",false), // 高温液位下限 CreateRegisterConfig(2300, uiTextBox17, "F2",false), // 转速 CreateRegisterConfig(2402, uiTextBox16, "F2",false), // 温度 CreateRegisterConfig(2408, uiTextBox14, "0",true), // 稳压时间 CreateRegisterConfig(2406, uiTextBox15, "0",true), // 通水时间 CreateRegisterConfig(2410, uiTextBox13, "0",true), // 排空时间 CreateRegisterConfig(2414, uiTextBox2, "0",true), // 延迟记录初始值时间 }; // 批量处理所有寄存器读取和UI更新 foreach (var config in registerConfigs) { await ReadRegisterAndUpdateUIAsync(config); } await ReadButtonStatusAsync(); } catch (Exception ex) { _readTimer?.Stop(); UIMessageBox.ShowError($"读取系数失败:{ex.Message}"); } } private RegisterConfig CreateRegisterConfig(int address, UITextBox textBox, string format, bool isInteger) { var config = new RegisterConfig(); config.Address = (ushort)address; // 显式转换为ushort,解决类型不匹配 config.TextBox = textBox; config.Format = format; config.IsInteger = isInteger; // 赋值整数类型标识 return config; } /// /// 通用方法:读取寄存器并更新SunnyUI文本框(核心逻辑复用) /// /// 寄存器配置 private async Task ReadRegisterAndUpdateUIAsync(RegisterConfig config) { ushort[] registers = await Task.Run(() => _modbusMaster?.ReadHoldingRegisters(1, config.Address, 2)); if (registers != null && registers.Length >= 2) { this.Invoke(new Action(() => { if (config.IsInteger) { int intValue = (registers[1] << 16) | registers[0]; config.TextBox.Text = intValue.ToString(config.Format); } else { float floatValue = c.UshortToFloat(registers[1], registers[0]); config.TextBox.Text = floatValue.ToString(config.Format); } })); } } private async Task ReadButtonStatusAsync() { try { // 读取水循环状态 - 地址0 bool[] waterStatus = await Task.Run(() => _modbusMaster?.ReadCoils(1, 10000, 1)); // 读取恒压启动状态 - 地址110 bool[] pressureStatus = await Task.Run(() => _modbusMaster?.ReadCoils(1, 10110, 1)); this.Invoke(new Action(() => { // 更新水循环按钮 if (waterStatus != null && waterStatus.Length > 0) { bool isWaterOn = waterStatus[0]; uiButton2.ForeColor = isWaterOn ? Color.Red : Color.White; uiButton2.Text = isWaterOn ? "水循环中" : "水循环"; } // 更新恒压启动按钮 if (pressureStatus != null && pressureStatus.Length > 0) { bool isPressureOn = pressureStatus[0]; uiButton3.ForeColor = isPressureOn ? Color.Red : Color.White; uiButton3.Text = isPressureOn ? "恒压启动中" : "恒压启动"; } })); } catch (Exception ex) { Debug.WriteLine($"[错误] 更新按钮状态失败: {ex.Message}"); } } private void Coeffiicientsetting_Load(object sender, EventArgs e) { string plcIp = "192.168.1.10"; //string plcIp = "127.0.0.1"; bool initSuccess = Data.ModbusResourceManager.Instance.Init(plcIp, 502); if (!initSuccess) { MessageBox.Show("连接Modbus服务器失败!", "错误"); this.Close(); return; } // 检查连接状态 if (_tcpClient == null || !_tcpClient.Connected) { MessageBox.Show("Modbus连接异常!", "错误"); this.Close(); return; } ma = new Function(_modbusMaster); c = new DataChange(); // 在 Load 完成 Modbus 初始化与 DataChange 初始化后再启动读定时器 _readTimer?.Start(); } private bool TryReconnect() { try { string plcIp = "192.168.1.10"; bool initSuccess = Data.ModbusResourceManager.Instance.Init(plcIp, 502); if (initSuccess) { ma = new Function(_modbusMaster); return true; } } catch (Exception ex) { MessageBox.Show($"重新连接失败:{ex.Message}"); } return false; } private void SwitchWindow(ref T windowInstance, Func createFunc) where T : UIForm { _isSwitchingWindow = true; _readTimer?.Stop(); _cts.Cancel(); // 2. 检查资源是否可用(添加重连机制) if (_tcpClient == null || !_tcpClient.Connected || _modbusMaster == null) { //尝试重新连接 bool reconnectSuccess = TryReconnect(); if (!reconnectSuccess) { MessageBox.Show("TCP连接已断开,请重新连接!", "提示"); return; } } // 3. 复用窗口实例:不存在则创建,存在则激活 if (windowInstance == null || windowInstance.IsDisposed) { windowInstance = createFunc(); windowInstance.FormClosed += (s, e) => { this.Invoke(new Action(() => { _isSwitchingWindow = false; _cts = new CancellationTokenSource(); _readTimer?.Start(); this.Show(); this.Activate(); })); }; } else { windowInstance.Activate(); return; } this.Hide(); windowInstance.Show(); } private void Coeffiicientsetting_FormClosing(object sender, FormClosingEventArgs e) { _cts.Cancel(); _cts.Dispose(); // 停止定时器 _readTimer?.Stop(); _readTimer?.Dispose(); // 仅用户主动关闭时退出应用 if (e.CloseReason == CloseReason.UserClosing) { ModbusResourceManager.Instance?.Dispose(); Application.Exit(); } } private void Coeffiicientsetting_FormClosed(object sender, FormClosedEventArgs e) { _normalTemperatureMode?.Dispose(); } //控制压力系数 private void uiTextBox1_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox1.Text.Trim(), 2394, Function.DataType.浮点型); } //压力保护输入 private void uiTextBox3_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox3.Text.Trim(), 3134, Function.DataType.浮点型); } //压力上限 //private void uiTextBox2_Click(object sender, EventArgs e) //{ // ma?.WriteToPLCForNew(uiTextBox2.Text.Trim(), 2376, Function.DataType.浮点型); //} //压力下限 //private void uiTextBox4_Click(object sender, EventArgs e) //{ // ma?.WriteToPLCForNew(uiTextBox4.Text.Trim(), 2374, Function.DataType.浮点型); //} //温度系数 private void uiTextBox8_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox8.Text.Trim(), 3482, Function.DataType.浮点型); } //出口温度系数 private void uiTextBox6_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox6.Text.Trim(), 3176, Function.DataType.浮点型); } //常温液位系数 private void uiTextBox7_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox7.Text.Trim(), 3076, Function.DataType.浮点型); } //常温液位上限 private void uiTextBox9_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox9.Text.Trim(), 3086, Function.DataType.浮点型); } //常温液位下限 private void uiTextBox10_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox10.Text.Trim(), 3084, Function.DataType.浮点型); } //高温液位系数 private void uiTextBox12_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox12.Text.Trim(), 3026, Function.DataType.浮点型); } //高温液位上限 private void uiTextBox11_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox11.Text.Trim(), 3036, Function.DataType.浮点型); } //高温液位下限 private void uiTextBox5_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox5.Text.Trim(), 3034, Function.DataType.浮点型); } //返回 private void uiButton1_Click(object sender, EventArgs e) { SwitchWindow(ref _normalTemperatureMode, () => new NormalTemperatureMode()); //this.Close(); } //稳压时间 private void uiTextBox14_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox14.Text.Trim(), 2408, Function.DataType.整形); } //通水时间 private void uiTextBox15_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox15.Text.Trim(), 2406, Function.DataType.整形); } //排空时间 private void uiTextBox13_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox13.Text.Trim(), 2410, Function.DataType.整形); } //温度 private void uiTextBox16_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox16.Text.Trim(), 2402, Function.DataType.整形); } //转速设置 private void uiTextBox17_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox17.Text.Trim(), 2300, Function.DataType.浮点型); } //水循环 private void uiButton2_Click(object sender, EventArgs e) { ma?.BtnClickFunctionForNew(Function.ButtonType.切换型, 10000); } //恒压启动 private void uiButton3_Click(object sender, EventArgs e) { ma?.BtnClickFunctionForNew(Function.ButtonType.切换型, 10110); } //延迟记录初始值时间 private void uiTextBox2_Click(object sender, EventArgs e) { ma?.WriteToPLCForNew(uiTextBox2.Text.Trim(), 2414, Function.DataType.整形); } #region //常温抽水 private void uiButton4_Click(object sender, EventArgs e) { ma?.BtnClickFunctionForNew(Function.ButtonType.切换型, 10006); } //高温抽水 private void uiButton13_Click(object sender, EventArgs e) { ma?.BtnClickFunctionForNew(Function.ButtonType.切换型, 10005); } //常温加水 private void uiButton5_Click(object sender, EventArgs e) { ma?.BtnClickFunctionForNew(Function.ButtonType.切换型, 10013); } //高温加水 private void uiButton11_Click(object sender, EventArgs e) { ma?.BtnClickFunctionForNew(Function.ButtonType.切换型, 10012); } //高压进阀 private void uiButton12_Click(object sender, EventArgs e) { ma?.BtnClickFunctionForNew(Function.ButtonType.切换型, 10008); } //高压出阀 private void uiButton7_Click(object sender, EventArgs e) { ma?.BtnClickFunctionForNew(Function.ButtonType.切换型, 10001); } //空气抽气 private void uiButton10_Click(object sender, EventArgs e) { ma?.BtnClickFunctionForNew(Function.ButtonType.切换型, 10007); } //常温回水 private void uiButton8_Click(object sender, EventArgs e) { ma?.BtnClickFunctionForNew(Function.ButtonType.切换型, 10010); } //高温回水 private void uiButton9_Click(object sender, EventArgs e) { ma?.BtnClickFunctionForNew(Function.ButtonType.切换型, 10009); } #endregion } }