using Microsoft.Win32;
using Modbus.Device;
using Modbus;
using OfficeOpenXml;
using System;
using System.Configuration;
using System.Data.SQLite;
using System.IO;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using 口罩泄露定制款;
using static ShanghaiEnvironmentalTechnology.Window5;
namespace ShanghaiEnvironmentalTechnology
{
///
/// 气阻测试与压力流量监控窗口(Modbus通信+数据记录)
///
public partial class Window2 : Window, IDisposable
{
private class FlowParameters
{
public float ExhaustP { get; set; }
}
DataChange c = new DataChange();
#region 寄存器/线圈地址定义(按功能分组)
// 压力相关地址
private readonly ushort _pressureRegisterAddress = 0x0780; // 连接口实时压力
private readonly ushort _noseRegisterAddress = 0x055C; // 鼻口实时压力
private readonly ushort _connectRegisterAddress = 73; // 连接口校准线圈(M72)
private readonly ushort _modifiedNoseRegisterAddress = 72; // 鼻口校准线圈(M73)
// 流量相关地址
private readonly ushort _flowAddress = 0x0078; // 实时流量读取
private readonly ushort _flowRegisterAddress = 364; // 流量记录地址
// 测试控制线圈
private readonly ushort _testStartAddress = 0x0050; // 测试启动(M80)
private readonly ushort _testStatusAddress = 0x0050; // 测试状态读取(同启动地址)
private readonly ushort _testStopAddress = 7; // 测试停止(M41)
#endregion
#region 私有字段
private TcpClient _tcpClient;
private IModbusMaster _modbusMaster;
private System.Timers.Timer _pressureReadTimer; // 连接口压力定时器
private System.Timers.Timer _noseReadTimer; // 鼻口压力定时器
private System.Timers.Timer _flowReadTimer; // 实时流量定时器
private System.Timers.Timer startTimer; // 启动状态实时定时器
private readonly System.Timers.Timer _flowTimer = new System.Timers.Timer(1000); // 流量参数定时器(1秒更新一次)
private readonly FlowParameters _flowParams = new FlowParameters();
#endregion
Function fc;
public Window2()
{
InitializeComponent();
InitializeModbusTcp();
Loaded += Window_Loaded;
}
#region 初始化与资源释放
///
/// 初始化Modbus连接和定时器
///
private void InitializeModbusTcp()
{
try
{
string plcIp = ConfigurationManager.AppSettings["PLC1_IP"];
int plcPort = int.Parse(ConfigurationManager.AppSettings["PLC1_Port"]);
_tcpClient = new TcpClient(plcIp, plcPort);
_modbusMaster = ModbusIpMaster.CreateIp(_tcpClient);
_modbusMaster.Transport.ReadTimeout = 3000;
_modbusMaster.Transport.WriteTimeout = 3000;
// 初始化定时器(1秒间隔)
_pressureReadTimer = CreateTimer(1000, OnPressureTimerElapsed);
_noseReadTimer = CreateTimer(1000, OnNoseTimerElapsed);
_flowReadTimer = CreateTimer(1000, OnFlowTimerElapsed);
startTimer = CreateTimer(1000, OnStartTimerElapsed);
// 流量参数定时器
_flowTimer.Elapsed += FlowTimer_Elapsed;
_flowTimer.AutoReset = true; // 自动重复
fc = new Function(_modbusMaster);
// 初始化数据库
InitializeDatabase();
}
catch (Exception ex)
{
ShowError($"Modbus初始化失败: {ex.Message}");
}
}
private void FlowTimer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
// 从下位机读取流量参数(假设对应以下寄存器地址,实际地址需根据设备手册修改)
_flowParams.ExhaustP = (float)ReadFromModbus(0x01, 314, true); // 排气P(浮点数)
// 更新UI(必须在UI线程)
Dispatcher.Invoke(() => UpdateFlowParametersUI());
}
catch (Exception ex)
{
Console.WriteLine($"流量参数读取失败: {ex.Message}");
}
}
private void UpdateFlowParametersUI()
{
// 检查TextBox是否有焦点:有焦点则不更新(避免覆盖用户输入)
if (!FowlTxt1.IsFocused) FowlTxt1.Text = _flowParams.ExhaustP.ToString("F2");
}
private object ReadFromModbus(byte slaveAddress, ushort registerAddress, bool isFloat)
{
try
{
// 读取保持寄存器(浮点数占2个寄存器,整数占1个)
ushort[] data = _modbusMaster?.ReadHoldingRegisters(
slaveAddress,
registerAddress,
isFloat ? (ushort)2 : (ushort)1
);
if (data != null)
{
// 根据类型转换数据
return isFloat
? Convert.ToSingle(c.UshortToFloat(data[1], data[0]))
: data[0];
}
else
{
return 0;
}
}
catch (Exception ex)
{
Console.WriteLine($"Modbus读取失败: {ex.Message}");
return null; // 读取失败时返回null
}
}
///
/// 通用定时器创建方法
///
private System.Timers.Timer CreateTimer(int intervalMs, ElapsedEventHandler elapsedAction)
{
var timer = new System.Timers.Timer(intervalMs)
{
AutoReset = true,
Enabled = true
};
timer.Elapsed += elapsedAction;
return timer;
}
///
/// 释放资源
///
public void Dispose()
{
// 释放定时器
_pressureReadTimer?.Dispose();
_noseReadTimer?.Dispose();
_flowReadTimer?.Dispose();
// 释放TCP连接
_tcpClient?.Close();
_tcpClient?.Dispose();
_modbusMaster = null;
}
///
/// 窗口关闭时释放资源
///
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
Dispose();
}
#endregion
#region 定时器读取逻辑
///
/// 连接口压力读取定时器
///
private void OnPressureTimerElapsed(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_pressureRegisterAddress, true,
value => UpdatePressureUI(value.ToString())
);
}
///
/// 鼻口压力读取定时器
///
private void OnNoseTimerElapsed(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_noseRegisterAddress, true,
value => UpdateNoseUI(value.ToString())
);
}
///
/// 实时流量读取定时器
///
private void OnFlowTimerElapsed(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_flowAddress, true,
value => UpdateFlowUI(value.ToString())
);
}
///
/// 实时流量读取定时器
///
private void OnStartTimerElapsed(object sender, ElapsedEventArgs e)
{
try
{
bool[] result = _modbusMaster?.ReadCoils(0x01, 81, 1);
bool isTestRunning = result != null && result.Length > 0 && result[0];
string testStartButtonText = "";
string ButtonStatus = "";
string currentLanguage = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
if (currentLanguage == "en-US")
{
testStartButtonText = "Test Start Success";
ButtonStatus = "Test initiation";
}
else if (currentLanguage == "zh-CN")
{
testStartButtonText = "测试启动成功";
ButtonStatus = "测试启动";
}
TestStartButton.Dispatcher.Invoke(() =>
{
if (isTestRunning)
{
TestStartButton.Content = testStartButtonText;
TestStartButton.Foreground = Brushes.LightGreen;
}
else
{
TestStartButton.Content = ButtonStatus;
TestStartButton.Foreground = Brushes.White;
}
});
}
catch (Exception ex)
{
Console.WriteLine($"读取线圈或更新UI失败:{ex.Message}");
}
}
///
/// 通用寄存器读取并更新UI,支持16位整数和32位浮点数
///
/// 起始地址
/// 是否为浮点型(占用2个寄存器)
/// 更新UI的回调函数
private void ReadAndUpdateRegister(ushort address, bool isFloat, Action