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

901 lines
32 KiB
C#
Raw Normal View History

2026-05-04 14:46:58 +08:00
using Modbus.Device;
using Modbus;
using OxyPlot.Series;
using OxyPlot;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;
using OxyPlot.Axes;
using OxyPlot.Legends;
using ;
namespace ShanghaiEnvironmentalTechnology
{
/// <summary>
/// Window6.xaml 的交互逻辑
/// </summary>
public partial class Window6 : Window
{
2026-05-08 19:10:44 +08:00
private readonly string _lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
2026-05-04 14:46:58 +08:00
DataChange c = new DataChange();
#region /线
// 控制线圈M代码
private readonly ushort _OutBreathUpAddress = 0x0011; // 呼上M17
private readonly ushort _OutBreathDownAddress = 0x0010; // 呼下M16
private readonly ushort _InBreathUpAddress = 0x001E; // 吸上M30
private readonly ushort _InBreathDownAddress = 0x001F; // 吸下M31
private readonly ushort _HandInBreathUpAddress = 0x0013; // 手动吸M19
private readonly ushort _HandInBreathDownAddress = 0x0012; // 手动呼M18
private readonly ushort _BreathUpAddress = 0x002A; // 呼气校准M42
private readonly ushort _BreathDownAddress = 0x002B; // 吸气校准M43
private readonly ushort _PressCheckAddress = 41; // 压力校准M41
Function fc;
#endregion
#region /线
// 控制线圈D代码
private readonly ushort _handSpeedAddress = 218; // 手动速度D218
//潮气量系数
private readonly ushort _moistureAddress = 3700;
//设置呼气流量系数 D1218呼流量系数
private readonly ushort _OutFowRateAddress = 1218; // 手动速度D1218呼流量系数
//设置吸气流量系数 D1318呼流量系数
private readonly ushort _InFowRateAddress = 1318; // 手动速度D1318呼流量系数
//设置压力系数 D1118
private readonly ushort _PressRateAddress = 1118; // 手动速度D1118
//位置
private readonly ushort _PositionAddress = 0x002A; // D42
//压力
private readonly ushort _PressAddress = 0x0BD6; // 手动速度D3030
//呼气流量
private readonly ushort _OutBreathAddress = 0x1398; // D5016
//吸气流量
private readonly ushort _InBreathAddress = 0x1396; // D5014
//复位
private readonly ushort _resetAddress = 0x0002; // D5014
#endregion
// 定时器(按功能分组)
private System.Timers.Timer _ReadTimer; // 实时监控数据
// Modbus通信
private TcpClient _tcpClient;
private IModbusMaster _modbusMaster;
private System.Timers.Timer resetTimer; // 启动状态实时定时器
#region
private PlotModel _plotModel;
private LineSeries _exhalationSeries;
private LineSeries _inhalationSeries;
private List<DataPoint> _exhalationData;
private List<DataPoint> _inhalationData;
private int _timeCounter;
#region ++
// 编辑状态标志位(控制定时器是否更新)
private bool _isEditingHandmovement; // 手动速度
private bool _isEditingMoisture; // 潮气量系数
private bool _isEditingOutFlow; // 呼气流量系数
private bool _isEditingInFlow; // 吸气流量系数
private bool _isEditingPress; // 压力系数
// 实时读取定时器1个定时器管理5个参数
private System.Timers.Timer _paramReadTimer;
#endregion
private void OnResetTimerElapsed(object sender, ElapsedEventArgs e)
{
try
{
bool[] result = _modbusMaster?.ReadCoils(0x01, 3, 1);
bool isTestRunning = result != null && result.Length > 0 && result[0];
ResetBtn.Dispatcher.Invoke(() =>
{
if (isTestRunning)
{
2026-05-09 10:30:14 +08:00
btn1.IsEnabled = false;
btn2.IsEnabled = false;
btn3.IsEnabled = false;
btn4.IsEnabled = false;
btn5.IsEnabled = false;
2026-05-08 19:10:44 +08:00
ResetBtn.Content = _lang == "en-US" ? "Reset Success" : "复位成功";
2026-05-04 14:46:58 +08:00
ResetBtn.Foreground = Brushes.LightGreen;
}
else
{
2026-05-09 10:30:14 +08:00
btn1.IsEnabled = true;
btn2.IsEnabled = true;
btn3.IsEnabled = true;
btn4.IsEnabled = true;
btn5.IsEnabled = true;
2026-05-08 19:10:44 +08:00
ResetBtn.Content = _lang == "en-US" ? "Reset" : "复位";
2026-05-04 14:46:58 +08:00
ResetBtn.Foreground = Brushes.White;
}
});
}
catch (Exception ex)
{
2026-05-08 19:10:44 +08:00
Console.WriteLine(_lang == "en-US" ? $"Read coil failed: {ex.Message}" : $"读取线圈或更新UI失败{ex.Message}");
2026-05-04 14:46:58 +08:00
}
}
#endregion
public Window6()
{
InitializeComponent();
InitializeModbusTcp();
InitializePlot();
StartDataUpdate();
_paramReadTimer = new System.Timers.Timer(1000) { AutoReset = true, Enabled = true };
_paramReadTimer.Elapsed += OnParamTimerElapsed; // 绑定定时读取事件
resetTimer = CreateTimer(1000, OnResetTimerElapsed);
Loaded += (s, e) => _paramReadTimer.Start();
//Hertbean();
}
#region UI
private void OnParamTimerElapsed(object sender, ElapsedEventArgs e)
{
// 1. 手动速度(焦点不在时更新)
if (!_isEditingHandmovement)
{
ReadAndUpdateParam(
address: _handSpeedAddress,
isFloat: true,
updateAction: (value) => UpdateTextBox(handmovementTxt, value.ToString())
);
}
// 2. 潮气量系数
if (!_isEditingMoisture)
{
ReadAndUpdateParam(
address: _moistureAddress,
isFloat: true,
updateAction: (value) => UpdateTextBox(moistureTxt, value.ToString())
);
}
// 3. 呼气流量系数
if (!_isEditingOutFlow)
{
ReadAndUpdateParam(
address: _OutFowRateAddress,
isFloat: true,
updateAction: (value) => UpdateTextBox(OutFowRateTxt, value.ToString())
);
}
// 4. 吸气流量系数
if (!_isEditingInFlow)
{
ReadAndUpdateParam(
address: _InFowRateAddress,
isFloat: true,
updateAction: (value) => UpdateTextBox(InFowRateTxt, value.ToString())
);
}
// 5. 压力系数
if (!_isEditingPress)
{
ReadAndUpdateParam(
address: _PressRateAddress,
isFloat: true,
updateAction: (value) => UpdateTextBox(PressRateTxt, value.ToString())
);
}
}
#endregion
// 读取下位机参数通用方法
private void ReadAndUpdateParam(ushort address, bool isFloat, Action<object> updateAction)
{
if (!IsModbusConnected())
{
2026-05-08 19:10:44 +08:00
updateAction(_lang == "en-US" ? "Offline" : "离线");
2026-05-04 14:46:58 +08:00
return;
}
try
{
ushort[] data = _modbusMaster?.ReadHoldingRegisters(0x01, address, isFloat ? (ushort)2 : (ushort)1);
2026-05-08 19:10:44 +08:00
object value = isFloat ? Convert.ToSingle(c.UshortToFloat(data[1], data[0])) : data[0];
2026-05-04 14:46:58 +08:00
updateAction(value);
}
catch
{
2026-05-08 19:10:44 +08:00
updateAction(_lang == "en-US" ? "Read Failed" : "读取失败");
2026-05-04 14:46:58 +08:00
}
}
private void UpdateTextBox(TextBox textBox, string value)
{
Dispatcher.Invoke(() =>
{
if (textBox.IsVisible) // 控件可见时才更新
{
textBox.Text = value;
}
});
}
private void InitializePlot()
{
_plotModel = new PlotModel
{
2026-05-08 19:10:44 +08:00
Title = _lang == "en-US" ? "Exhalation & Inhalation Flow" : "呼气流量与吸气流量",
Background = OxyColor.FromRgb(240, 240, 240)
2026-05-04 14:46:58 +08:00
};
_exhalationSeries = new LineSeries
{
2026-05-08 19:10:44 +08:00
Title = _lang == "en-US" ? "Exhalation Flow (D5016)" : "呼气流量 (D5016)",
2026-05-04 14:46:58 +08:00
Color = OxyColor.FromRgb(255, 0, 0),
2026-05-08 19:10:44 +08:00
StrokeThickness = 2,
MarkerType = MarkerType.Circle,
2026-05-04 14:46:58 +08:00
MarkerSize = 4
};
_inhalationSeries = new LineSeries
{
2026-05-08 19:10:44 +08:00
Title = _lang == "en-US" ? "Inhalation Flow (D5014)" : "吸气流量 (D5014)",
2026-05-04 14:46:58 +08:00
Color = OxyColor.FromRgb(0, 0, 255),
StrokeThickness = 2,
MarkerType = MarkerType.Circle,
MarkerSize = 4
};
_exhalationData = new List<DataPoint>();
_inhalationData = new List<DataPoint>();
_plotModel.Series.Add(_exhalationSeries);
_plotModel.Series.Add(_inhalationSeries);
2026-05-08 19:10:44 +08:00
_plotModel.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = _lang == "en-US" ? "Time (s)" : "时间 (秒)" });
_plotModel.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = _lang == "en-US" ? "Flow" : "流量" });
2026-05-04 14:46:58 +08:00
2026-05-08 19:10:44 +08:00
_plotModel.IsLegendVisible = true;
2026-05-04 14:46:58 +08:00
plotView.Model = _plotModel;
}
2026-05-08 19:10:44 +08:00
2026-05-04 14:46:58 +08:00
private void StartDataUpdate()
{
DispatcherTimer timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
timer.Tick += async (s, e) => await UpdateData();
timer.Start();
}
private async Task UpdateData()
{
if (!IsModbusConnected()) return;
try
{
// 读取寄存器值(保持不变)
ushort[] exhalationData = await Task.Run(() => _modbusMaster?.ReadHoldingRegisters(0x01, _OutBreathAddress, 2));
ushort[] inhalationData = await Task.Run(() => _modbusMaster?.ReadHoldingRegisters(0x01, _InBreathAddress, 2));
// 解析呼气流量(保持不变)
ushort a = exhalationData[0];
ushort b = exhalationData[1];
float floatValue = c.UshortToFloat(b, a);
floatValue = (float)Math.Round(floatValue, 2);
// 解析吸气流量(保持不变)
ushort a1 = inhalationData[0];
ushort b1 = inhalationData[1];
float floatValue1 = c.UshortToFloat(b1, a1);
floatValue1 = (float)Math.Round(floatValue1, 2);
double exhalationValue = floatValue;
double inhalationValue = floatValue1;
// 关键修改添加新数据后只保留最新的10个数据点
_exhalationData.Add(new DataPoint(_timeCounter, exhalationValue));
_inhalationData.Add(new DataPoint(_timeCounter, inhalationValue));
_timeCounter++; // 时间计数器统一递增(避免两条线时间轴不一致)
// 限制数据列表长度为10只保留最新数据
if (_exhalationData.Count > 10)
{
_exhalationData.RemoveRange(0, _exhalationData.Count - 10); // 移除旧数据
}
if (_inhalationData.Count > 10)
{
_inhalationData.RemoveRange(0, _inhalationData.Count - 10);
}
// 更新图表数据(保持不变)
_exhalationSeries.Points.Clear();
_inhalationSeries.Points.Clear();
foreach (var point in _exhalationData)
{
_exhalationSeries.Points.Add(point);
}
foreach (var point in _inhalationData)
{
_inhalationSeries.Points.Add(point);
}
_plotModel.InvalidatePlot(true);
}
catch (Exception ex)
{
Console.WriteLine($"读取数据失败: {ex.Message}");
}
}
/// <summary>
/// 初始化Modbus连接和定时器
/// </summary>
private void InitializeModbusTcp()
{
try
{
// 从配置读取PLC连接信息
string plcIp = ConfigurationManager.AppSettings["PLC2_IP"];
int plcPort = int.Parse(ConfigurationManager.AppSettings["PLC2_Port"]);
_tcpClient = new TcpClient(plcIp, plcPort);
_modbusMaster = ModbusIpMaster.CreateIp(_tcpClient);
_modbusMaster.Transport.ReadTimeout = 3000;
_modbusMaster.Transport.WriteTimeout = 3000;
fc = new Function(_modbusMaster);
// 初始化定时器
InitializeTimers();
// 初始化数据库
//InitializeDatabase();
}
catch (Exception ex)
{
ShowError($"Modbus初始化失败: {ex.Message}");
}
}
/// <summary>
/// 统一初始化所有定时器(避免重复配置)
/// </summary>
private void InitializeTimers()
{
_ReadTimer = CreateTimer(1000, OnRealTimerElapsed);
}
/// <summary>
///
/// </summary>
private void OnRealTimerElapsed(object sender, ElapsedEventArgs e)
{
ReadAndUpdateDualRegister(
_PositionAddress,
_PressAddress, _OutBreathAddress, _InBreathAddress,
(a, b, c, d) => UpdateTimerUI(a.ToString(), b.ToString(), c.ToString(), d.ToString())
);
}
/// <summary>
/// 更新呼吸计时UI
/// </summary>
private void UpdateTimerUI(string a, string b, string c, string d)
{
UpdateUiSafely(() =>
{
2026-05-08 19:10:44 +08:00
positionTxt.Text = IsModbusConnected() ? a : (_lang == "en-US" ? "Disconnected" : "连接断开");
pressTxt.Text = IsModbusConnected() ? b : (_lang == "en-US" ? "Disconnected" : "连接断开");
OutFowTxt.Text = IsModbusConnected() ? c : (_lang == "en-US" ? "Disconnected" : "连接断开");
InFlowTxt.Text = IsModbusConnected() ? d : (_lang == "en-US" ? "Disconnected" : "连接断开");
2026-05-04 14:46:58 +08:00
});
}
/// <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}");
}
}
/// <summary>
/// 读取两个寄存器并更新UI统一处理连接状态
/// </summary>
private void ReadAndUpdateDualRegister(ushort address1, ushort address2, ushort address3, ushort address4, Action<float, float, float, float> updateAction)
{
if (!IsModbusConnected())
{
updateAction?.Invoke(0, 0, 0, 0); // 触发UI显示"连接断开"
return;
}
try
{
ushort[] data1 = _modbusMaster?.ReadHoldingRegisters(0x01, address1, 2);
ushort[] data2 = _modbusMaster?.ReadHoldingRegisters(0x01, address2, 2);
ushort[] data3 = _modbusMaster?.ReadHoldingRegisters(0x01, address3, 2);
ushort[] data4 = _modbusMaster?.ReadHoldingRegisters(0x01, address4, 2);
// 2. 解析寄存器值data[0]是D312data[1]是D313
ushort a1 = data1[0]; // 高位寄存器值
ushort b1 = data1[1]; // 低位寄存器值
float floatValue1 = c.UshortToFloat(b1, a1);
floatValue1 = (float)Math.Round(floatValue1, 2);
// 2. 解析寄存器值data[0]是D312data[1]是D313
ushort a2 = data2[0]; // 高位寄存器值
ushort b2 = data2[1]; // 低位寄存器值
float floatValue2 = c.UshortToFloat(b2, a2);
floatValue2 = (float)Math.Round(floatValue2, 2);
// 2. 解析寄存器值data[0]是D312data[1]是D313
ushort a3 = data3[0]; // 高位寄存器值
ushort b3 = data3[1]; // 低位寄存器值
float floatValue3 = c.UshortToFloat(b3, a3);
floatValue3 = (float)Math.Round(floatValue3, 2);
// 2. 解析寄存器值data[0]是D312data[1]是D313
ushort a4 = data4[0]; // 高位寄存器值
ushort b4 = data4[1]; // 低位寄存器值
float floatValue4 = c.UshortToFloat(b4, a4);
floatValue4 = (float)Math.Round(floatValue4, 2);
updateAction?.Invoke(floatValue1, floatValue2, floatValue3, floatValue4);
}
catch (Exception ex)
{
Console.WriteLine($"读取寄存器[{address1:X4},{address2:X4}]失败: {ex.Message}");
updateAction?.Invoke(0, 0, 0, 0); // 触发UI显示"读取失败"
}
}
/// <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;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
string imagePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources/sleep2.jpg");
if (System.IO.File.Exists(imagePath))
{
Background = new ImageBrush
{
ImageSource = new BitmapImage(new Uri(imagePath, UriKind.Absolute))
};
}
else
{
Console.WriteLine($"背景图片不存在: {imagePath}");
}
}
catch (Exception ex)
{
Console.WriteLine($"加载背景失败: {ex.Message}");
}
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
new Window5().ShowDialog();
Close();
}
private async Task WriteRegisterWithValidation(
TextBox inputControl,
ushort registerAddress,
float minValue,
float maxValue)
{
if (!IsModbusConnected())
{
ShowError("Modbus TCP 未连接");
return;
}
2026-05-08 19:10:44 +08:00
inputControl.Text = _lang == "en-US" ? "Processing..." : "操作中...";
2026-05-04 14:46:58 +08:00
try
{
Function ma = new Function(_modbusMaster);
ma.WriteToPLCForNew("", registerAddress, Function.DataType.);
//// 等待并刷新
//await Task.Delay(300);
//ReadAndUpdateRegister(registerAddress, true, v => UpdatePressureUI(v.ToString()));
}
catch (Exception ex)
{
ShowError($"操作失败: {ex.Message}");
}
finally
{
2026-05-09 10:30:14 +08:00
2026-05-04 14:46:58 +08:00
}
}
/// <summary>
/// 写入单个寄存器
/// </summary>
private async Task WriteSingleRegisterWithOutUI(
ushort registerAddress,
Func<int, string> successMessage)
{
if (!IsModbusConnected())
{
2026-05-09 10:30:14 +08:00
// ShowError("Modbus TCP 未连接");
2026-05-04 14:46:58 +08:00
return;
}
try
{
await _modbusMaster.WriteSingleCoilAsync(0x01, registerAddress, true);
await Task.Delay(100); // 等待PLC处理
await _modbusMaster.WriteSingleCoilAsync(0x01, registerAddress, false);
await Task.Delay(100); // 等待PLC处理
}
catch (Exception ex)
{
2026-05-08 19:10:44 +08:00
ShowError(_lang == "en-US" ? $"Set failed: {ex.Message}" : $"设置失败: {ex.Message}");
2026-05-04 14:46:58 +08:00
}
finally
{
}
}
/// <summary>
/// 检查Modbus连接状态统一判断逻辑
/// </summary>
private bool IsModbusConnected()
{
return _modbusMaster != null && _tcpClient?.Connected == true;
}
2026-05-08 19:10:44 +08:00
private void ShowSuccess(string msg) => MessageBox.Show(msg, _lang == "en-US" ? "Success" : "成功", MessageBoxButton.OK, MessageBoxImage.Information);
private void ShowWarning(string msg) => MessageBox.Show(msg, _lang == "en-US" ? "Warning" : "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
private void ShowError(string msg) => MessageBox.Show(msg, _lang == "en-US" ? "Error" : "错误", MessageBoxButton.OK, MessageBoxImage.Error);
2026-05-04 14:46:58 +08:00
private void Button_Click_2(object sender, RoutedEventArgs e)
{
var mainWindow = MainWindow.Instance;
// 检查窗口状态只在窗口未显示时调用ShowDialog
if (!mainWindow.IsVisible)
{
mainWindow.ShowDialog();
}
else
{
// 如果窗口已显示,可将其激活到前台
mainWindow.Activate();
}
Close();
}
private void Button_Click_3(object sender, RoutedEventArgs e)
{
new ReportWindow5().ShowDialog();
Close();
}
2026-05-08 19:10:44 +08:00
private async void Button_Click_4(object sender, RoutedEventArgs e) => await WriteSingleRegisterWithOutUI(_OutBreathUpAddress, v => $"Exhale Up: {v}");
private async void Button_Click_5(object sender, RoutedEventArgs e) => await WriteSingleRegisterWithOutUI(_OutBreathDownAddress, v => $"Exhale Down: {v}");
private async void Button_Click_6(object sender, RoutedEventArgs e) => await WriteSingleRegisterWithOutUI(_InBreathUpAddress, v => $"Inhale Up: {v}");
private async void Button_Click_7(object sender, RoutedEventArgs e) => await WriteSingleRegisterWithOutUI(_InBreathDownAddress, v => $"Inhale Down: {v}");
private async void Button_Click_8(object sender, RoutedEventArgs e) => await WriteSingleRegisterWithOutUI(_HandInBreathUpAddress, v => $"Manual Inhale: {v}");
private async void Button_Click_9(object sender, RoutedEventArgs e) => await WriteSingleRegisterWithOutUI(_HandInBreathDownAddress, v => $"Manual Exhale: {v}");
2026-05-04 14:46:58 +08:00
private async void Button_Click_10(object sender, RoutedEventArgs e)
{
if (!IsModbusConnected())
{
2026-05-08 19:10:44 +08:00
UpdateResetButtonStatus(_lang == "en-US" ? "Disconnected" : "连接断开", Brushes.Red);
ShowError(_lang == "en-US" ? "Modbus TCP not connected" : "Modbus TCP 未连接");
2026-05-04 14:46:58 +08:00
return;
}
try
{
2026-05-08 19:10:44 +08:00
UpdateResetButtonStatus(_lang == "en-US" ? "Resetting..." : "正在复位...", Brushes.LightGreen);
await Task.Run(() => _modbusMaster.WriteSingleCoil(0x01, _resetAddress, true));
2026-05-04 14:46:58 +08:00
fc.BtnClickFunctionForNew(Function.ButtonType., _resetAddress);
await Task.Delay(100);
2026-05-08 19:10:44 +08:00
await Task.Run(() => _modbusMaster.WriteSingleCoil(0x01, _resetAddress, false));
2026-05-04 14:46:58 +08:00
fc.BtnClickFunctionForNew(Function.ButtonType., _resetAddress);
2026-05-08 19:10:44 +08:00
UpdateResetButtonStatus(_lang == "en-US" ? "Reset Success" : "复位成功", Brushes.LightGreen);
2026-05-04 14:46:58 +08:00
}
catch (Exception ex)
{
2026-05-08 19:10:44 +08:00
Console.WriteLine(_lang == "en-US" ? $"Reset error: {ex.Message}" : $"复位异常: {ex.Message}");
UpdateResetButtonStatus(_lang == "en-US" ? "Reset Failed" : "复位失败", Brushes.Red);
ShowError(_lang == "en-US" ? $"Operation error: {ex.Message}" : $"操作异常: {ex.Message}");
2026-05-04 14:46:58 +08:00
}
}
/// <summary>
/// 更新复位按钮状态UI
/// </summary>
private void UpdateResetButtonStatus(string text, Brush color)
{
UpdateUiSafely(() =>
{
ResetBtn.Content = text;
ResetBtn.Foreground = color;
});
}
private async void Button_Click_11(object sender, RoutedEventArgs e)
{
2026-05-08 19:10:44 +08:00
await WriteCoilWithCheck(_BreathUpAddress, true,
_lang == "en-US" ? "Calibration success" : "校准指令已被设备接收并执行",
_lang == "en-US" ? "Calibration timeout" : "校准执行超时,状态异常",
_lang == "en-US" ? "Calibration executed" : "校准指令执行成功");
2026-05-04 14:46:58 +08:00
}
2026-05-08 19:10:44 +08:00
2026-05-04 14:46:58 +08:00
private async void Button_Click_12(object sender, RoutedEventArgs e)
{
2026-05-08 19:10:44 +08:00
await WriteCoilWithCheck(_BreathDownAddress, true,
_lang == "en-US" ? "Calibration success" : "校准指令已被设备接收并执行",
_lang == "en-US" ? "Calibration timeout" : "校准执行超时,状态异常",
_lang == "en-US" ? "Calibration executed" : "校准指令执行成功");
2026-05-04 14:46:58 +08:00
}
private async void Button_Click_13(object sender, RoutedEventArgs e)
{
2026-05-08 19:10:44 +08:00
await WriteCoilWithCheck(_PressCheckAddress, true,
_lang == "en-US" ? "Calibration success" : "校准指令已被设备接收并执行",
_lang == "en-US" ? "Calibration timeout" : "校准执行超时,状态异常",
_lang == "en-US" ? "Calibration executed" : "校准指令执行成功");
2026-05-04 14:46:58 +08:00
}
2026-05-08 19:10:44 +08:00
2026-05-04 14:46:58 +08:00
/// <summary>
/// 写入线圈并验证状态
/// </summary>
2026-05-08 19:10:44 +08:00
private async Task WriteCoilWithCheck(ushort coil, bool val, string ok, string err, string log)
{
if (!IsModbusConnected()) { ShowError(_lang == "en-US" ? "Modbus TCP not connected" : "Modbus TCP 未连接"); return; }
2026-05-04 14:46:58 +08:00
try
{
2026-05-08 19:10:44 +08:00
await Task.Run(() => _modbusMaster.WriteSingleCoilAsync(0x01, coil, val));
2026-05-04 14:46:58 +08:00
Thread.Sleep(200);
2026-05-08 19:10:44 +08:00
if (err.Contains("Calib") || err.Contains("校准")) await Task.Run(() => _modbusMaster.WriteSingleCoilAsync(0x01, coil, false));
2026-05-04 14:46:58 +08:00
Thread.Sleep(100);
await Task.Delay(500);
2026-05-08 19:10:44 +08:00
bool[] status = await _modbusMaster?.ReadCoilsAsync(0x01, coil, 1);
if (status != null && status[0] == val) { WriteLog(log); ShowSuccess(ok); }
else ShowError(err);
2026-05-04 14:46:58 +08:00
}
2026-05-08 19:10:44 +08:00
catch (Exception ex) { ShowError(_lang == "en-US" ? $"Communication error: {ex.Message}" : $"通信错误: {ex.Message}"); }
2026-05-04 14:46:58 +08:00
}
/// <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}");
}
}
2026-05-08 19:10:44 +08:00
2026-05-04 14:46:58 +08:00
private async void Button_Click_14(object sender, RoutedEventArgs e)
{
try
{
await WriteRegisterWithValidation(
inputControl: handmovementTxt,
registerAddress: _handSpeedAddress, // 手动速度寄存器地址(根据实际修改)
minValue: 1, // 手动速度最小值
maxValue: 1000 // 手动速度最大值
);
}
finally
{
}
}
private async void Button_Click_15(object sender, RoutedEventArgs e)
{
try
{
await WriteRegisterWithValidation(
inputControl: moistureTxt,
registerAddress: _moistureAddress, // 手动速度寄存器地址(根据实际修改)
minValue: 1, // 手动速度最小值
maxValue: 1000 // 手动速度最大值
);
}
finally
{
}
}
private async void Button_Click_16(object sender, RoutedEventArgs e)
{
try
{
await WriteRegisterWithValidation(
inputControl: OutFowRateTxt,
registerAddress: _OutFowRateAddress, // 手动速度寄存器地址(根据实际修改)
minValue: 1, // 手动速度最小值
maxValue: 1000 // 手动速度最大值
);
}
finally
{
}
}
private async void Button_Click_17(object sender, RoutedEventArgs e)
{
try
{
await WriteRegisterWithValidation(
inputControl: InFowRateTxt,
registerAddress: _InFowRateAddress, // 手动速度寄存器地址(根据实际修改)
minValue: 1, // 手动速度最小值
maxValue: 1000 // 手动速度最大值
);
}
finally
{
}
}
private async void Button_Click_18(object sender, RoutedEventArgs e)
{
try
{
await WriteRegisterWithValidation(
inputControl: PressRateTxt,
registerAddress: _PressRateAddress, // 手动速度寄存器地址(根据实际修改)
minValue: 1, // 手动速度最小值
maxValue: 1000 // 手动速度最大值
);
}
finally
{
}
}
}
}