Files
Sleep-Multi-functionality/Window4.xaml.cs
2026-05-09 14:34:05 +08:00

960 lines
35 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 Window4 : Window, IDisposable
{
DataChange c = new DataChange();
#region /线
// 基础参数地址
private readonly ushort _pressureSettingRegisterAddress = 0x013A; // 单一故障气阻设置流量D314
private readonly ushort _noseRegisterAddress = 0x055C; // 鼻口压力地址
private readonly ushort _modifiedNoseRegisterAddress = 0x0048; // 鼻口压力校准地址M72
private readonly ushort _outRegisterAddress = 120; // 呼流量地址
private readonly ushort _inRegisterAddress = 1400; // 吸流量地址
private readonly ushort _BreathOutRegisterAddress = 316; // 记录呼气阻力实时显示
private readonly ushort _BreathInRegisterAddress = 318; // 记录吸气阻力实时显示
// 线圈地址(控制指令)
private readonly ushort _testStartAddress = 0x0020; // 单一故障气阻测试启动M32
#endregion
#region
private TcpClient _tcpClient;
private IModbusMaster _modbusMaster;
Function fc;
// 定时器
private System.Timers.Timer _outReadTimer; // 呼流量读取
private System.Timers.Timer _inReadTimer; // 吸流量读取
private System.Timers.Timer _noseReadTimer; // 鼻口压力读取
private System.Timers.Timer _settingReadTimer2; //
private System.Timers.Timer startTimer; // 启动状态实时定时器
#endregion
public Window4()
{
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;
// 初始化定时器
InitializeTimers();
fc = new Function(_modbusMaster);
// 初始化数据库
InitializeDatabase();
}
catch (Exception ex)
{
ShowError($"Modbus初始化失败: {ex.Message}");
}
}
/// <summary>
/// 统一初始化所有定时器
/// </summary>
private void InitializeTimers()
{
_outReadTimer = CreateTimer(1000, OnOutTimerElapsed);
_inReadTimer = CreateTimer(1000, OnInTimerElapsed);
_noseReadTimer = CreateTimer(1000, OnNoseTimerElapsed);
_settingReadTimer2 = CreateTimer(1000, OnSettingReadTimerTimerElapsed2);
startTimer = CreateTimer(1000, OnStartTimerElapsed);
}
/// <summary>
/// 实时流量读取定时器修正跨线程访问UI问题
/// </summary>
private void OnStartTimerElapsed(object sender, ElapsedEventArgs e)
{
try
{
bool[] result = _modbusMaster?.ReadCoils(0x01, 33, 1);
bool isTestRunning = result != null && result.Length > 0 && result[0];
string lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string running = lang == "en-US" ? "Test Running" : "测试启动成功";
string ready = lang == "en-US" ? "Start Test" : "测试启动";
TestStartButton.Dispatcher.Invoke(() =>
{
if (isTestRunning)
{
btnsetting.IsEnabled = false;
btnsetting2.IsEnabled = false;
TestStartButton.Content = running;
TestStartButton.Foreground = Brushes.LightGreen;
}
else
{
btnsetting.IsEnabled = true;
btnsetting2.IsEnabled = true;
TestStartButton.Content = ready;
TestStartButton.Foreground = Brushes.White;
}
});
}
catch (Exception ex)
{
Console.WriteLine($"读取线圈或更新UI失败{ex.Message}");
}
}
private void OnSettingReadTimerTimerElapsed2(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_pressureSettingRegisterAddress, true,
value => UpdateSettingUI2(value.ToString())
);
}
private void UpdateSettingUI2(string value)
{
string lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string disconnect = lang == "en-US" ? "Disconnected" : "连接断开";
UpdateUiSafely(() => clostTxt.Text = IsModbusConnected() ? value : disconnect);
}
/// <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()
{
// 释放定时器
_outReadTimer?.Dispose();
_inReadTimer?.Dispose();
_noseReadTimer?.Dispose();
// 释放Modbus连接
_tcpClient?.Close();
_tcpClient?.Dispose();
_modbusMaster = null;
}
/// <summary>
/// 窗口关闭时释放资源
/// </summary>
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
Dispose();
}
#endregion
#region +UI更新
/// <summary>
/// 呼流量读取定时器
/// </summary>
private void OnOutTimerElapsed(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_outRegisterAddress, true,
value => UpdateOutUI(value.ToString())
);
}
/// <summary>
/// 吸流量读取定时器
/// </summary>
private void OnInTimerElapsed(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_inRegisterAddress, true,
value => UpdateInUI(value.ToString())
);
}
/// <summary>
/// 鼻口压力读取定时器
/// </summary>
private void OnNoseTimerElapsed(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_noseRegisterAddress, true,
value => UpdateNoseUI(value.ToString())
);
}
/// <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更新线
/// <summary>
/// 更新呼流量UI
/// </summary>
private void UpdateOutUI(string value)
{
string lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string disconnect = lang == "en-US" ? "Disconnected" : "连接断开";
UpdateUiSafely(() => outTxt.Text = IsModbusConnected() ? value : disconnect);
}
/// <summary>
/// 更新吸流量UI
/// </summary>
private void UpdateInUI(string value)
{
string lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string disconnect = lang == "en-US" ? "Disconnected" : "连接断开";
UpdateUiSafely(() => InTxt.Text = IsModbusConnected() ? value : disconnect);
}
/// <summary>
/// 更新鼻口压力UI
/// </summary>
private void UpdateNoseUI(string value)
{
string lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string disconnect = lang == "en-US" ? "Disconnected" : "连接断开";
UpdateUiSafely(() => NoseTxt.Text = IsModbusConnected() ? value : disconnect);
}
/// <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>
///// 流量值设置settingTxt
///// </summary>
//private async void Button_Click(object sender, RoutedEventArgs e)
//{
// await WriteRegisterWithValidation(
// inputControl: settingTxt,
// registerAddress: _pressureSettingRegisterAddress,
// minValue: 0,
// maxValue: 10000,
// successMsg: value => $"设置流量值: {value} L/min"
// );
//}
/// <summary>
/// 鼻口压力校准M72线圈
/// </summary>
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
string lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string success = lang == "en-US" ? "Calibration OK (verified)" : "校准指令已被设备接收并执行(二次验证通过)";
string fail = lang == "en-US" ? "Calibration timeout" : "校准执行超时,状态异常";
string log = lang == "en-US" ? "Calibration done" : "校准指令执行成功";
await WriteCoilWithCheck(_modifiedNoseRegisterAddress, true, success, fail, log);
}
/// <summary>
/// 单一故障气阻测试停止M34线圈
/// </summary>
private async void Button_Click_3(object sender, RoutedEventArgs e)
{
string lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string fail = lang == "en-US" ? "Test stop timeout" : "单一故障气阻测试停止超时,状态异常";
string log = lang == "en-US" ? "Test stopped" : "单一故障气阻测试停止";
string start = lang == "en-US" ? "Start Test" : "测试启动";
await WriteCoilWithCheck(0x0022, true, null, fail, log);
TestStartButton.Content = start;
TestStartButton.Foreground = Brushes.White;
}
/// <summary>
/// 单一故障气阻测试启动M20线圈
/// </summary>
private async void Button_Click_4(object sender, RoutedEventArgs e)
{
string lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
if (!IsModbusConnected())
{
UpdateButtonStatus(lang == "en-US" ? "Disconnected" : "连接断开", Brushes.Red);
ShowError(lang == "en-US" ? "Modbus TCP not connected" : "Modbus TCP 未连接");
return;
}
try
{
UpdateButtonStatus(lang == "en-US" ? "Starting..." : "正在启动...", Brushes.LightGreen);
await Task.Run(() => _modbusMaster.WriteSingleCoilAsync(0x01, _testStartAddress, true));
await Task.Delay(100);
await Task.Run(() => _modbusMaster.WriteSingleCoilAsync(0x01, _testStartAddress, false));
await Task.Delay(100);
UpdateButtonStatus(lang == "en-US" ? "Test Started" : "测试启动成功", Brushes.LightGreen);
}
catch (Exception ex)
{
UpdateButtonStatus(lang == "en-US" ? "Start Failed" : "测试启动失败", Brushes.Red);
ShowError(lang == "en-US" ? $"Error: {ex.Message}" : $"操作异常: {ex.Message}");
}
}
/// <summary>
/// 读取呼气阻力D136并保存
/// </summary>
private async void Button_Click_5(object sender, RoutedEventArgs e)
{
string lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
if (!IsModbusConnected())
{
saveFlowOutTxt.Text = lang == "en-US" ? "Disconnected" : "连接断开";
ShowError(lang == "en-US" ? "Modbus TCP not connected" : "Modbus TCP 未连接");
return;
}
fc.BtnClickFunctionForNew(Function.ButtonType., 192);
fc.BtnClickFunctionForNew(Function.ButtonType., 192);
ReadAndUpdateRegister(_BreathOutRegisterAddress, true, value => UpdateFlowFlowUI(value.ToString()));
ReadAndUpdateRegister(_BreathInRegisterAddress, true, value => UpdateCloseFlowUI2(value.ToString()));
if (float.TryParse(saveFlowOutTxt.Text, out float flowValue) &&
float.TryParse(saveFlowInTxt.Text, out float pressureValue))
{
SaveRecordToDatabase(flowValue, pressureValue);
}
else
{
ShowError(lang == "en-US" ? "Invalid data format" : "流量或压力值格式不正确,请检查输入");
}
List<CO2Record> records = ReadCO2RecordsFromDatabase();
if (records == null || records.Count == 0)
{
string msg = lang == "en-US" ? "No data to export" : "单一故障气阻表中无数据,无法导出";
MessageBox.Show(msg, "Info", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
bool exportSuccess = ExportCO2RecordsToExcel(records);
if (exportSuccess)
{
string msg = lang == "en-US" ? "Export successful" : "数据已成功导出到Excel";
MessageBox.Show(msg, "Success", MessageBoxButton.OK, MessageBoxImage.Information);
}
else
{
string msg = lang == "en-US" ? "Export failed" : "Excel导出失败请检查文件是否被占用";
MessageBox.Show(msg, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private bool ExportCO2RecordsToExcel(List<CO2Record> records)
{
try
{
SaveFileDialog saveDialog = new SaveFileDialog
{
Filter = "Excel(*.xlsx)|*.xlsx",
FileName = $"AirResistance_{DateTime.Now:yyyyMMddHHmmss}.xlsx",
Title = "Export Air Resistance Data"
};
if (saveDialog.ShowDialog() != true) return false;
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
using (var package = new ExcelPackage(new FileInfo(saveDialog.FileName)))
{
var ws = package.Workbook.Worksheets.Add("Records");
ws.Cells[1, 1].Value = "Expiratory Pa";
ws.Cells[1, 2].Value = "Inspiratory Pa";
ws.Cells[1, 3].Value = "Time";
for (int i = 0; i < records.Count; i++)
{
ws.Cells[i + 2, 1].Value = records[i].Flow;
ws.Cells[i + 2, 2].Value = records[i].Pressure;
ws.Cells[i + 2, 3].Value = records[i].RecordTime.ToString("yyyy-MM-dd HH:mm:ss");
}
ws.Cells.AutoFitColumns();
package.Save();
}
return true;
}
catch (Exception ex)
{
string lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string err = lang == "en-US" ? "Export failed" : "导出失败";
MessageBox.Show($"{err}: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
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 ExpiratoryResistance 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;
}
}
private void UpdateFlowFlowUI(string value)
{
string lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string disconnect = lang == "en-US" ? "Disconnected" : "连接断开";
UpdateUiSafely(() => saveFlowOutTxt.Text = IsModbusConnected() ? value : disconnect);
}
private void UpdateCloseFlowUI2(string value)
{
string lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
string disconnect = lang == "en-US" ? "Disconnected" : "连接断开";
UpdateUiSafely(() => saveFlowInTxt.Text = IsModbusConnected() ? value : disconnect);
}
///// <summary>
///// 读取吸气阻力D318并保存
///// </summary>
//private async void Button_Click_6(object sender, RoutedEventArgs e)
//{
// await ReadAndSaveRegister(
// address: _flowInRegisterAddress,
// control: saveFlowInTxt,
// isFlow: false
// );
//}
/// <summary>
/// 返回主窗口
/// </summary>
private void Button_Click_2(object sender, RoutedEventArgs e)
{
var mainWindow = MainWindow.Instance;
// 检查窗口状态只在窗口未显示时调用ShowDialog
if (!mainWindow.IsVisible)
{
mainWindow.ShowDialog();
}
else
{
// 如果窗口已显示,可将其激活到前台
mainWindow.Activate();
}
Close();
}
/// <summary>
/// 打开报告窗口
/// </summary>
private void Button_Click_7(object sender, RoutedEventArgs e)
{
new ReportWindow4().ShowDialog();
}
#endregion
#region
private async Task WriteRegisterWithValidation(
TextBox inputControl,
ushort registerAddress,
float minValue,
float maxValue)
{
string lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
if (!IsModbusConnected())
{
ShowError(lang == "en-US" ? "Modbus TCP not connected" : "Modbus TCP 未连接");
return;
}
if (!float.TryParse(inputControl.Text.Trim(), out float value) || value < minValue || value > maxValue)
{
string msg = lang == "en-US" ? $"Enter {minValue}~{maxValue}" : $"请输入{minValue}~{maxValue}的数字";
ShowWarning(msg);
return;
}
try
{
inputControl.Text = lang == "en-US" ? "Processing..." : "操作中...";
Function ma = new Function(_modbusMaster);
ma.WriteToPLCForNew(value.ToString(), registerAddress, Function.DataType.);
await Task.Delay(300);
ReadAndUpdateRegister(registerAddress, true, v => UpdatePressureUI(v.ToString()));
}
catch (Exception ex)
{
string err = lang == "en-US" ? $"Failed: {ex.Message}" : $"操作失败: {ex.Message}";
ShowError(err);
}
finally
{
inputControl.Text = value.ToString();
}
}
private void UpdatePressureUI(string value)
{
UpdateUiSafely(() => clostTxt.Text = value);
}
/// <summary>
/// 写入线圈并验证状态
/// </summary>
private async Task WriteCoilWithCheck(
ushort coilAddress,
bool value,
string successMsg,
string failMsg,
string logMsg)
{
string lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
if (_modbusMaster == null)
{
// ShowError(lang == "en-US" ? "Modbus TCP not connected" : "Modbus TCP 未连接");
return;
}
if (!IsModbusConnected())
{
InitializeModbusTcp();
return;
}
try
{
// 写入线圈
await Task.Run(() =>
_modbusMaster.WriteSingleCoilAsync(0x01, coilAddress, value)
);
Thread.Sleep(200);
// ==============================
// 兼容:中文 停止/校准 + 英文 Stop/Calib
// ==============================
bool needReset = false;
if (failMsg != null)
{
bool hasStop = failMsg.Contains("停止") || failMsg.Contains("Stop") || failMsg.Contains("stop");
bool hasCalib = failMsg.Contains("校准") || failMsg.Contains("Calib") || failMsg.Contains("calib");
needReset = hasStop || hasCalib;
}
if (failMsg != null && needReset)
{
// 写入线圈
await Task.Run(() =>
_modbusMaster.WriteSingleCoilAsync(0x01, coilAddress, false)
);
}
Thread.Sleep(100);
// 等待并验证
await Task.Delay(500);
bool[] status = await _modbusMaster?.ReadCoilsAsync(0x01, coilAddress, 1);
// ==============================
// 同样兼容中英文判断
// ==============================
bool noResetCheck = false;
if (failMsg != null)
{
bool hasStop = failMsg.Contains("停止") || failMsg.Contains("Stop") || failMsg.Contains("stop");
bool hasCalib = failMsg.Contains("校准") || failMsg.Contains("Calib") || failMsg.Contains("calib");
noResetCheck = !hasStop && !hasCalib;
}
if (failMsg != null && noResetCheck)
{
if (status != null && status.Length > 0 && status[0] == value)
{
// 写入日志
WriteLog($"{logMsg} - 地址:{coilAddress},状态:{value}");
if (!string.IsNullOrEmpty(successMsg))
{
ShowSuccess(successMsg);
}
}
else
{
ShowError(failMsg);
}
}
}
catch (Exception ex)
{
ShowError(lang == "en-US" ? $"Communication error: {ex.Message}" : $"通信错误: {ex.Message}");
}
}
#endregion
#region
/// <summary>
/// 初始化数据库
/// </summary>
private void InitializeDatabase()
{
try
{
using (var conn = new SQLiteConnection(CSConstant.DbConnectionString))
{
conn.Open();
string createSql = @"
CREATE TABLE IF NOT EXISTS ExpiratoryResistance (
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 ExpiratoryResistance(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 => System.IO.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";
System.IO.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)
{
try
{
string imgPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources/sleep2.jpg");
if (System.IO.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}");
}
}
/// <summary>
/// clostTxt输入验证仅允许数字和小数点
/// </summary>
private void ClostTxt_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
var isNumber = System.Text.RegularExpressions.Regex.IsMatch(e.Text, @"^[0-9]*(?:\.[0-9]*)?$");
e.Handled = !isNumber;
}
private void UpdateClosePressureUI(string value)
{
UpdateUiSafely(() => clostTxt.Text = value);
}
// 消息提示封装
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
/// <summary>
/// 下拉框选择变化事件处理
/// </summary>
private async void CaptureModeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender == null) return;
var comboBox = sender as ComboBox;
if (comboBox == null) return;
var selectedItem = comboBox.SelectedItem as ComboBoxItem;
if (selectedItem == null) return;
var content = selectedItem.Content?.ToString();
if (string.IsNullOrEmpty(content)) return;
switch (content)
{
case "呼气":
case "Exhale":
await WriteCoilWithCheck(36, false, null, "Breath Type", "Breath Type");
break;
case "吸气":
case "Inhale":
await WriteCoilWithCheck(36, true, null, "Breath Type", "Breath Type");
break;
default:
return;
}
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
await WriteRegisterWithValidation(
inputControl: clostTxt,
registerAddress: _pressureSettingRegisterAddress,
minValue: 0,
maxValue: 10000
);
//_settingReadTimer2.Start();
}
finally
{
}
}
}
}