Files
Sleep-Multi-functionality/Window2.xaml.cs

957 lines
34 KiB
C#
Raw Normal View History

2026-05-04 14:46:58 +08:00
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
{
/// <summary>
/// 气阻测试与压力流量监控窗口Modbus通信+数据记录)
/// </summary>
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
/// <summary>
/// 初始化Modbus连接和定时器
/// </summary>
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
}
}
/// <summary>
/// 通用定时器创建方法
/// </summary>
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;
}
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
// 释放定时器
_pressureReadTimer?.Dispose();
_noseReadTimer?.Dispose();
_flowReadTimer?.Dispose();
// 释放TCP连接
_tcpClient?.Close();
_tcpClient?.Dispose();
_modbusMaster = null;
}
/// <summary>
/// 窗口关闭时释放资源
/// </summary>
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
Dispose();
}
#endregion
#region
/// <summary>
/// 连接口压力读取定时器
/// </summary>
private void OnPressureTimerElapsed(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_pressureRegisterAddress, true,
value => UpdatePressureUI(value.ToString())
);
}
/// <summary>
/// 鼻口压力读取定时器
/// </summary>
private void OnNoseTimerElapsed(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_noseRegisterAddress, true,
value => UpdateNoseUI(value.ToString())
);
}
/// <summary>
/// 实时流量读取定时器
/// </summary>
private void OnFlowTimerElapsed(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_flowAddress, true,
value => UpdateFlowUI(value.ToString())
);
}
/// <summary>
/// 实时流量读取定时器
/// </summary>
private void OnStartTimerElapsed(object sender, ElapsedEventArgs e)
{
try
{
bool[] result = _modbusMaster?.ReadCoils(0x01, 81, 1);
bool isTestRunning = result != null && result.Length > 0 && result[0];
2026-05-07 16:51:45 +08:00
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 = "测试启动";
}
2026-05-04 14:46:58 +08:00
TestStartButton.Dispatcher.Invoke(() =>
{
if (isTestRunning)
{
2026-05-09 10:30:14 +08:00
btnjiaozhun.IsEnabled = false;
btnlianjiekou.IsEnabled = false;
btnsetting.IsEnabled = false;
2026-05-07 16:51:45 +08:00
TestStartButton.Content = testStartButtonText;
2026-05-04 14:46:58 +08:00
TestStartButton.Foreground = Brushes.LightGreen;
}
else
{
2026-05-09 10:30:14 +08:00
btnjiaozhun.IsEnabled = true;
btnlianjiekou.IsEnabled = true;
btnsetting.IsEnabled = true;
2026-05-07 16:51:45 +08:00
TestStartButton.Content = ButtonStatus;
2026-05-04 14:46:58 +08:00
TestStartButton.Foreground = Brushes.White;
}
});
}
catch (Exception ex)
{
Console.WriteLine($"读取线圈或更新UI失败{ex.Message}");
}
}
/// <summary>
/// 通用寄存器读取并更新UI支持16位整数和32位浮点数
/// </summary>
/// <param name="address">起始地址</param>
/// <param name="isFloat">是否为浮点型占用2个寄存器</param>
/// <param name="updateAction">更新UI的回调函数</param>
private void ReadAndUpdateRegister(ushort address, bool isFloat, Action<object> updateAction)
{
if (!IsModbusConnected())
{
updateAction?.Invoke(isFloat ? (object)float.NaN : (ushort)0);
return;
}
try
{
// 根据数据类型确定读取的寄存器数量
int registerCount = isFloat ? 2 : 1;
ushort[] data = _modbusMaster?.ReadHoldingRegisters(0x01, address, (ushort)registerCount);
if (isFloat)
{
// 浮点型转换2个16位寄存器组合为32位浮点数
if (data.Length >= 2)
{
// 2. 解析寄存器值data[0]是D312data[1]是D313
ushort a = data[0]; // 高位寄存器值
ushort b = data[1]; // 低位寄存器值
float floatValue = c.UshortToFloat(b, a);
floatValue = (float)Math.Round(floatValue, 2);
updateAction?.Invoke(floatValue);
}
else
{
updateAction?.Invoke(float.NaN);
}
}
else
{
// 16位整数直接返回
updateAction?.Invoke(data.Length > 0 ? data[0] : (ushort)0);
}
}
catch (Exception ex)
{
Console.WriteLine($"读取寄存器[{address:X4}]失败: {ex.Message}");
// 异常时根据类型返回对应的值
updateAction?.Invoke(isFloat ? (object)float.NaN : (ushort)0);
}
}
#endregion
#region UI更新线
2026-05-07 16:51:45 +08:00
private void UpdateConnectionTextUI(System.Windows.Controls.TextBox textBox, string value)
{
// 获取当前语言(默认中文)
string currentLanguage = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
// 多语言提示信息
string disconnectMsg = currentLanguage == "en-US" ? "Connection disconnected" : "连接断开";
// 安全更新UI
UpdateUiSafely(() =>
textBox.Text = IsModbusConnected() ? value : disconnectMsg
);
}
private void UpdateConnectionTextUI(System.Windows.Controls.TextBlock textBox, string value)
{
// 获取当前语言(默认中文)
string currentLanguage = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
// 多语言提示信息
string disconnectMsg = currentLanguage == "en-US" ? "Connection disconnected" : "连接断开";
// 安全更新UI
UpdateUiSafely(() =>
textBox.Text = IsModbusConnected() ? value : disconnectMsg
);
}
2026-05-04 14:46:58 +08:00
/// <summary>
/// 更新连接口压力UI
/// </summary>
private void UpdatePressureUI(string value)
{
UpdateUiSafely(() =>
2026-05-07 16:51:45 +08:00
UpdateConnectionTextUI(RealTimePressureTextBox, value)
2026-05-04 14:46:58 +08:00
);
}
/// <summary>
/// 更新鼻口压力UI
/// </summary>
private void UpdateNoseUI(string value)
{
UpdateUiSafely(() =>
2026-05-07 16:51:45 +08:00
UpdateConnectionTextUI(NoseTxt, value)
2026-05-04 14:46:58 +08:00
);
}
/// <summary>
/// 更新实时流量UI
/// </summary>
private void UpdateFlowUI(string value)
{
UpdateUiSafely(() =>
2026-05-07 16:51:45 +08:00
UpdateConnectionTextUI(flowTxt, value)
2026-05-04 14:46:58 +08:00
);
}
/// <summary>
/// 更新测试按钮状态UI
/// </summary>
private void UpdateButtonStatus(string text, Brush color)
{
UpdateUiSafely(() =>
{
TestStartButton.Content = text;
TestStartButton.Foreground = color;
});
}
/// <summary>
/// 线程安全的UI更新通用方法统一实现
/// </summary>
private void UpdateUiSafely(Action action)
{
if (action == null) return;
if (Dispatcher.HasShutdownStarted)
{
return;
}
try
{
if (!Dispatcher.CheckAccess())
{
Dispatcher.Invoke(action, TimeSpan.FromSeconds(2));
}
else
{
action.Invoke();
}
}
catch (TaskCanceledException)
{
}
catch (Exception ex)
{
Console.WriteLine($"UI更新失败{ex.Message}");
}
}
#endregion
#region
/// <summary>
/// 连接口压力校准M73线圈
/// </summary>
private async void Button_Click(object sender, RoutedEventArgs e)
{
2026-05-07 21:17:08 +08:00
string currentLanguage = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string success = currentLanguage == "en-US"
? "Calibration command received (verified)"
: "校准指令已被设备接收并执行(二次验证通过)";
string fail = currentLanguage == "en-US"
? "Calibration timeout, abnormal status"
: "校准执行超时,状态异常";
string log = currentLanguage == "en-US"
? "Connection port pressure calibration success"
: "连接口压力校准指令执行成功";
2026-05-04 14:46:58 +08:00
await WriteCoilWithCheck(
_connectRegisterAddress,
true,
2026-05-07 21:17:08 +08:00
success,
fail,
log
2026-05-04 14:46:58 +08:00
);
}
/// <summary>
/// 鼻口压力校准M72线圈
/// </summary>
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
2026-05-07 21:17:08 +08:00
string currentLanguage = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string success = currentLanguage == "en-US"
? "Calibration command received (verified)"
: "校准指令已被设备接收并执行(二次验证通过)";
string fail = currentLanguage == "en-US"
? "Calibration timeout, abnormal status"
: "校准执行超时,状态异常";
string log = currentLanguage == "en-US"
? "Nose pressure calibration success"
: "鼻口压力校准指令执行成功";
2026-05-04 14:46:58 +08:00
await WriteCoilWithCheck(
_modifiedNoseRegisterAddress,
true,
2026-05-07 21:17:08 +08:00
success,
fail,
log
2026-05-04 14:46:58 +08:00
);
}
/// <summary>
/// 流量数据读取并保存AirTxt
/// </summary>
private async void Button_Click_2(object sender, RoutedEventArgs e)
{
2026-05-07 21:17:08 +08:00
string currentLanguage = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string noConn = currentLanguage == "en-US" ? "Modbus TCP not connected" : "Modbus TCP 未连接";
string invalid = currentLanguage == "en-US" ? "Invalid pressure, not saved" : "当前压力值无效,未保存数据";
string noData = currentLanguage == "en-US" ? "No data to export" : "气阻表中无数据,无法导出";
string exportSuccess = currentLanguage == "en-US" ? "Export success" : "数据已成功导出到Excel";
2026-05-04 14:46:58 +08:00
if (!IsModbusConnected())
{
2026-05-07 21:17:08 +08:00
AirTxt.Text = currentLanguage == "en-US" ? "Disconnected" : "连接断开";
ShowError(noConn);
2026-05-04 14:46:58 +08:00
return;
}
fc.BtnClickFunctionForNew(Function.ButtonType., 191);
fc.BtnClickFunctionForNew(Function.ButtonType., 191);
ReadAndUpdateRegister(
_flowRegisterAddress, true,
value => UpdateFlowFlowUI(value.ToString()));
// 尝试将文本框内容转换为float
if (double.TryParse(AirTxt.Text, out double floatValue) &&
float.TryParse(flowTxt.Text, out float pressureValue))
{
SaveRecordToDatabase(floatValue, pressureValue);
}
else
{
2026-05-07 21:17:08 +08:00
ShowWarning(invalid);
2026-05-04 14:46:58 +08:00
}
// 步骤2读取CO2表数据
List<CO2Record> co2Records = ReadCO2RecordsFromDatabase();
if (co2Records == null || !co2Records.Any())
{
2026-05-07 21:17:08 +08:00
MessageBox.Show(noData, currentLanguage == "en-US" ? "Info" : "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
2026-05-04 14:46:58 +08:00
return;
}
// 步骤3导出Excel
2026-05-07 21:17:08 +08:00
bool exportSuccessFlag = ExportCO2RecordsToExcel(co2Records);
if (exportSuccessFlag)
2026-05-04 14:46:58 +08:00
{
2026-05-07 21:17:08 +08:00
MessageBox.Show(exportSuccess, currentLanguage == "en-US" ? "Success" : "成功", MessageBoxButton.OK, MessageBoxImage.Information);
2026-05-04 14:46:58 +08:00
}
}
private bool ExportCO2RecordsToExcel(List<CO2Record> records)
{
try
{
SaveFileDialog saveDialog = new SaveFileDialog
{
Filter = "Excel文件 (*.xlsx)|*.xlsx",
FileName = $"气阻记录_{DateTime.Now:yyyyMMddHHmmss}.xlsx",
Title = "保存气阻记录"
};
bool? result = saveDialog.ShowDialog(); if (!(result ?? false)) return false;
2026-05-07 16:51:45 +08:00
2026-05-07 21:17:08 +08:00
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
2026-05-04 14:46:58 +08:00
using (ExcelPackage package = new ExcelPackage(new FileInfo(saveDialog.FileName)))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("气阻记录");
worksheet.Cells[1, 1].Value = "气阻hpa";
worksheet.Cells[1, 2].Value = "流量L/min";
worksheet.Cells[1, 3].Value = "时间";
using (var headerRange = worksheet.Cells[1, 1, 1, 6])
{
headerRange.Style.Font.Bold = true;
headerRange.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
}
for (int i = 0; i < records.Count; i++)
{
int row = i + 2;
var record = records[i];
worksheet.Cells[row, 1].Value = record.Flow;
worksheet.Cells[row, 2].Value = record.Pressure;
worksheet.Cells[row, 3].Value = record.RecordTime.ToString("yyyy-MM-dd HH:mm:ss");
}
worksheet.Cells.AutoFitColumns();
package.Save();
}
return true;
}
catch (Exception ex)
{
2026-05-07 21:17:08 +08:00
string currentLanguage = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string err = currentLanguage == "en-US" ? "Export failed" : "导出失败";
MessageBox.Show($"{err}{ex.Message}", currentLanguage == "en-US" ? "Error" : "错误", MessageBoxButton.OK, MessageBoxImage.Error);
2026-05-04 14:46:58 +08:00
return false;
}
}
/// <summary>
///
/// </summary>
private List<CO2Record> ReadCO2RecordsFromDatabase()
{
List<CO2Record> records = new List<CO2Record>();
try
{
using (SQLiteConnection conn = new SQLiteConnection(CSConstant.DbConnectionString))
{
conn.Open();
// 查询CO2表所有记录按时间排序
string query = "SELECT Flow, Pressure, RecordTime FROM AirRecords ORDER BY RecordTime desc limit 1";
using (SQLiteCommand cmd = new SQLiteCommand(query, conn))
{
using (SQLiteDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
records.Add(new CO2Record
{
Flow = reader.GetDouble(0), // 二氧化碳浓度(%
Pressure = reader.GetDouble(1), // 压力pa
RecordTime = reader.GetDateTime(2) // 时间
});
}
}
}
}
return records;
}
catch (Exception ex)
{
MessageBox.Show($"读取气阻表失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
return null;
}
}
/// <summary>
/// 更新实时流量UI
/// </summary>
private void UpdateFlowFlowUI(string value)
{
UpdateUiSafely(() =>
AirTxt.Text = IsModbusConnected() ? value : "连接断开"
);
}
/// <summary>
/// 返回主窗口
/// </summary>
private void Button_Click_3(object sender, RoutedEventArgs e)
{
var mainWindow = MainWindow.Instance;
// 检查窗口状态只在窗口未显示时调用ShowDialog
if (!mainWindow.IsVisible)
{
mainWindow.ShowDialog();
}
else
{
// 如果窗口已显示,可将其激活到前台
mainWindow.Activate();
}
Close();
}
/// <summary>
/// 测试启动M80线圈
/// </summary>
private async void Button_Click_4(object sender, RoutedEventArgs e)
{
2026-05-07 21:17:08 +08:00
string currentLanguage = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
2026-05-04 14:46:58 +08:00
if (!IsModbusConnected())
{
2026-05-07 21:17:08 +08:00
UpdateButtonStatus(currentLanguage == "en-US" ? "Disconnected" : "连接断开", Brushes.Red);
ShowError(currentLanguage == "en-US" ? "Modbus TCP not connected" : "Modbus TCP 未连接");
2026-05-04 14:46:58 +08:00
return;
}
try
{
2026-05-07 21:17:08 +08:00
UpdateButtonStatus(currentLanguage == "en-US" ? "Starting..." : "正在启动...", Brushes.LightGreen);
2026-05-04 14:46:58 +08:00
await Task.Run(() =>
_modbusMaster.WriteSingleCoilAsync(0x01, _testStartAddress, true)
);
await Task.Delay(100);
await Task.Run(() =>
_modbusMaster.WriteSingleCoilAsync(0x01, _testStatusAddress, false)
);
await Task.Delay(100);
2026-05-07 21:17:08 +08:00
UpdateButtonStatus(currentLanguage == "en-US" ? "Test started successfully" : "测试启动成功", Brushes.LightGreen);
2026-05-04 14:46:58 +08:00
}
catch (Exception ex)
{
2026-05-07 21:17:08 +08:00
UpdateButtonStatus(currentLanguage == "en-US" ? "Test start failed" : "测试启动失败", Brushes.Red);
ShowError(currentLanguage == "en-US" ? $"Operation error: {ex.Message}" : $"操作异常: {ex.Message}");
2026-05-04 14:46:58 +08:00
}
}
/// <summary>
/// 测试停止M41线圈
/// </summary>
private async void Button_Click_5(object sender, RoutedEventArgs e)
{
2026-05-07 21:17:08 +08:00
string currentLanguage = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string failMsg = currentLanguage == "en-US"
? "Air resistance test stop timeout"
: "气阻测试停止超时,状态异常";
string logMsg = currentLanguage == "en-US"
? "Air resistance test stopped"
: "气阻测试停止";
2026-05-04 14:46:58 +08:00
await WriteCoilWithCheck(
_testStopAddress,
true,
2026-05-07 21:17:08 +08:00
null,
failMsg,
logMsg
2026-05-04 14:46:58 +08:00
);
2026-05-07 21:17:08 +08:00
TestStartButton.Content = currentLanguage == "en-US" ? "Test initiation" : "测试启动";
2026-05-04 14:46:58 +08:00
TestStartButton.Foreground = Brushes.White;
}
/// <summary>
/// 打开报告窗口
/// </summary>
private void Button_Click_6(object sender, RoutedEventArgs e)
{
new ReportWindow2().ShowDialog();
}
#endregion
#region
/// <summary>
/// 写入线圈并验证状态
/// </summary>
private async Task WriteCoilWithCheck(
2026-05-07 21:17:08 +08:00
ushort coilAddress,
bool value,
string successMsg,
string failMsg,
string logMsg)
2026-05-04 14:46:58 +08:00
{
2026-05-07 21:17:08 +08:00
string currentLanguage = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string noConn = currentLanguage == "en-US" ? "Modbus TCP not connected" : "Modbus TCP 未连接";
string commError = currentLanguage == "en-US" ? "Communication error" : "通信错误";
2026-05-04 14:46:58 +08:00
if (!IsModbusConnected())
{
2026-05-07 21:17:08 +08:00
ShowError(noConn);
2026-05-04 14:46:58 +08:00
return;
}
try
{
await Task.Run(() =>
_modbusMaster.WriteSingleCoilAsync(0x01, coilAddress, value)
);
Thread.Sleep(200);
2026-05-07 21:17:08 +08:00
if (failMsg != null)
2026-05-04 14:46:58 +08:00
{
2026-05-07 21:17:08 +08:00
bool isStop = failMsg.Contains("停止") || failMsg.Equals("Stop", StringComparison.OrdinalIgnoreCase);
bool isCalib = failMsg.Contains("校准") || failMsg.Equals("Calibrate", StringComparison.OrdinalIgnoreCase);
if (isStop || isCalib)
{
await Task.Run(() =>
_modbusMaster.WriteSingleCoilAsync(0x01, coilAddress, false)
);
}
2026-05-04 14:46:58 +08:00
}
Thread.Sleep(100);
await Task.Delay(500);
bool[] status = await _modbusMaster?.ReadCoilsAsync(0x01, coilAddress, 1);
2026-05-07 21:17:08 +08:00
if (failMsg != null)
2026-05-04 14:46:58 +08:00
{
2026-05-07 21:17:08 +08:00
bool isStop = failMsg.Contains("停止") || failMsg.Equals("Stop", StringComparison.OrdinalIgnoreCase);
bool isCalib = failMsg.Contains("校准") || failMsg.Equals("Calibrate", StringComparison.OrdinalIgnoreCase);
if (!isStop && !isCalib)
2026-05-04 14:46:58 +08:00
{
2026-05-07 21:17:08 +08:00
if (status[0] == value)
2026-05-04 14:46:58 +08:00
{
2026-05-07 21:17:08 +08:00
WriteLog($"{logMsg} - Address{coilAddress}Status{value}");
if (!string.IsNullOrEmpty(successMsg)) ShowSuccess(successMsg);
}
else
{
ShowError(failMsg);
2026-05-04 14:46:58 +08:00
}
}
}
}
catch (Exception ex)
{
2026-05-07 21:17:08 +08:00
ShowError($"{commError}: {ex.Message}");
2026-05-04 14:46:58 +08:00
}
}
#endregion
#region
/// <summary>
/// 初始化数据库
/// </summary>
private void InitializeDatabase()
{
try
{
using (var conn = new SQLiteConnection(CSConstant.DbConnectionString))
{
conn.Open();
string createSql = @"
CREATE TABLE IF NOT EXISTS AirRecords (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Flow REAL NOT NULL,
Pressure REAL NOT NULL,
RecordTime DATETIME NOT NULL
);";
using (var cmd = new SQLiteCommand(createSql, conn))
{
cmd.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
Console.WriteLine($"数据库初始化失败: {ex.Message}");
ShowError($"数据库错误: {ex.Message}");
}
}
/// <summary>
/// 保存记录到数据库
/// </summary>
private void SaveRecordToDatabase(double flow, double pressure)
{
try
{
flow = Math.Round(flow, 2);
pressure = Math.Round(pressure, 2);
using (var conn = new SQLiteConnection(CSConstant.DbConnectionString))
{
conn.Open();
string insertSql = @"
INSERT INTO AirRecords (Flow, Pressure, RecordTime)
VALUES (@Flow, @Pressure, @RecordTime);";
using (var cmd = new SQLiteCommand(insertSql, conn))
{
cmd.Parameters.AddWithValue("@Flow", flow);
cmd.Parameters.AddWithValue("@Pressure", pressure);
cmd.Parameters.AddWithValue("@RecordTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
cmd.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
Console.WriteLine($"保存数据库失败: {ex.Message}");
ShowWarning($"数据保存失败: {ex.Message}");
}
}
/// <summary>
/// 日志路径
/// </summary>
private string logPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "modbus_log.txt");
/// <summary>
/// 写入操作日志
/// </summary>
private void WriteLog(string content)
{
try
{
string log = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {content}\r\n";
File.AppendAllText(logPath, log);
}
catch (Exception ex)
{
Console.WriteLine($"写入日志失败: {ex.Message}");
}
}
#endregion
#region
/// <summary>
/// 检查Modbus连接状态
/// </summary>
private bool IsModbusConnected()
{
return _modbusMaster != null && _tcpClient?.Connected == true;
}
/// <summary>
/// 加载窗口背景
/// </summary>
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_flowTimer.Start();
try
{
string imgPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources/sleep2.jpg");
if (File.Exists(imgPath))
{
Background = new ImageBrush
{
ImageSource = new BitmapImage(new Uri(imgPath, UriKind.Absolute))
};
}
else
{
Console.WriteLine($"背景图片不存在: {imgPath}");
}
}
catch (Exception ex)
{
Console.WriteLine($"加载背景失败: {ex.Message}");
}
}
// 消息提示封装
private void ShowSuccess(string msg) => MessageBox.Show(msg, "成功", MessageBoxButton.OK, MessageBoxImage.Information);
private void ShowWarning(string msg) => MessageBox.Show(msg, "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
private void ShowError(string msg) => MessageBox.Show(msg, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
#endregion
private void Button_Click_7(object sender, RoutedEventArgs e)
{
fc.WriteToPLCForNew(FowlTxt1.Text, 314, Function.DataType.);
}
}
}