Files
Sleep-Multi-functionality/Window6.xaml.cs
2026-05-11 19:06:26 +08:00

978 lines
34 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 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 ;
using .Data;
namespace ShanghaiEnvironmentalTechnology
{
/// <summary>
/// Window6.xaml 的交互逻辑
/// </summary>
public partial class Window6 : Window
{
private readonly string _lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
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; // 启动状态实时定时器
string currentLang = LanguageManager.CurrentLanguage;
#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)
{
btn1.IsEnabled = false;
btn2.IsEnabled = false;
btn3.IsEnabled = false;
btn4.IsEnabled = false;
btn5.IsEnabled = false;
ResetBtn.Content = _lang == "en-US" ? "Reset Success" : "复位成功";
ResetBtn.Foreground = Brushes.LightGreen;
}
else
{
btn1.IsEnabled = true;
btn2.IsEnabled = true;
btn3.IsEnabled = true;
btn4.IsEnabled = true;
btn5.IsEnabled = true;
ResetBtn.Content = _lang == "en-US" ? "Reset" : "复位";
ResetBtn.Foreground = Brushes.White;
}
});
}
catch (Exception ex)
{
Console.WriteLine(_lang == "en-US" ? $"Read coil failed: {ex.Message}" : $"读取线圈或更新UI失败{ex.Message}");
}
}
#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())
);
}
OnStartTimerElapsed(sender, e);
}
private void OnStartTimerElapsed(object sender, ElapsedEventArgs e)
{
string _lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
try
{
bool[] result = _modbusMaster?.ReadCoils(0x01, 98, 1);
bool isRunning = result != null && result.Length > 0 && result[0];
Dispatcher.Invoke(() =>
{
if (isRunning)
{
btn1.IsEnabled = false;
btn2.IsEnabled = false;
btn3.IsEnabled = false;
btn4.IsEnabled = false;
btn5.IsEnabled = false;
}
else
{
btn1.IsEnabled = true;
btn2.IsEnabled = true;
btn3.IsEnabled = true;
btn4.IsEnabled = true;
btn5.IsEnabled = true;
}
});
}
catch (Exception ex)
{
Console.WriteLine(_lang == "en-US" ? $"Failed to read coil: {ex.Message}" : $"读取线圈或更新UI失败{ex.Message}");
}
}
#endregion
// 读取下位机参数通用方法
private void ReadAndUpdateParam(ushort address, bool isFloat, Action<object> updateAction)
{
if (!IsModbusConnected())
{
//updateAction("离线");
//// 2. 直接判断是否是英文
if (LanguageManager.IsEnglish)
{
// 英文逻辑
updateAction("Offline");
}
else if (LanguageManager.IsChinese)
{
// 中文逻辑
updateAction("离线");
}
return;
}
try
{
ushort[] data = _modbusMaster?.ReadHoldingRegisters(0x01, address, isFloat ? (ushort)2 : (ushort)1);
object value = isFloat ? Convert.ToSingle(c.UshortToFloat(data[1], data[0])) : data[0];
updateAction(value);
}
catch
{
updateAction(_lang == "en-US" ? "Read Failed" : "读取失败");
}
}
private void UpdateTextBox(TextBox textBox, string value)
{
try
{
Dispatcher.Invoke(() =>
{
if (textBox.IsVisible) // 控件可见时才更新
{
textBox.Text = value;
}
});
}
catch (Exception ex)
{
Console.WriteLine($"更新TextBox失败: {ex.Message}");
}
}
private void InitializePlot()
{
_plotModel = new PlotModel
{
Title = _lang == "en-US" ? "Exhalation & Inhalation Flow" : "呼气流量与吸气流量",
Background = OxyColor.FromRgb(240, 240, 240)
};
_exhalationSeries = new LineSeries
{
Title = _lang == "en-US" ? "Exhalation Flow (D5016)" : "呼气流量 (D5016)",
Color = OxyColor.FromRgb(255, 0, 0),
StrokeThickness = 2,
MarkerType = MarkerType.Circle,
MarkerSize = 4
};
_inhalationSeries = new LineSeries
{
Title = _lang == "en-US" ? "Inhalation Flow (D5014)" : "吸气流量 (D5014)",
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);
_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" : "流量" });
_plotModel.IsLegendVisible = true;
plotView.Model = _plotModel;
}
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 _modbusMaster?.ReadHoldingRegistersAsync(0x01, _OutBreathAddress, 2);
ushort[] inhalationData = await _modbusMaster?.ReadHoldingRegistersAsync(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(() =>
{
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" : "连接断开");
});
}
/// <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;
}
inputControl.Text = _lang == "en-US" ? "Processing..." : "操作中...";
try
{
Function ma = new Function(_modbusMaster);
ma.WriteToPLCForNew(handmovementTxt.Text, registerAddress, Function.DataType.);
//// 等待并刷新
//await Task.Delay(300);
//ReadAndUpdateRegister(registerAddress, true, v => UpdatePressureUI(v.ToString()));
}
catch (Exception ex)
{
ShowError($"操作失败: {ex.Message}");
}
finally
{
}
}
/// <summary>
/// 写入单个寄存器
/// </summary>
private async Task WriteSingleRegisterWithOutUI(
ushort registerAddress,
Func<int, string> successMessage)
{
if (!IsModbusConnected())
{
// ShowError("Modbus TCP 未连接");
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)
{
ShowError(_lang == "en-US" ? $"Set failed: {ex.Message}" : $"设置失败: {ex.Message}");
}
finally
{
}
}
/// <summary>
/// 检查Modbus连接状态统一判断逻辑
/// </summary>
private bool IsModbusConnected()
{
return _modbusMaster != null && _tcpClient?.Connected == true;
}
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);
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();
}
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 bool _isManualInhaleOn;
private async void Button_Click_8(object sender, RoutedEventArgs e)
=> fc.BtnClickFunctionForNew(Function.ButtonType., _HandInBreathUpAddress);
private async void Button_Click_9(object sender, RoutedEventArgs e)
=>fc.BtnClickFunctionForNew(Function.ButtonType., _HandInBreathDownAddress);
private async void Button_Click_10(object sender, RoutedEventArgs e)
{
if (!IsModbusConnected())
{
UpdateResetButtonStatus(_lang == "en-US" ? "Disconnected" : "连接断开", Brushes.Red);
ShowError(_lang == "en-US" ? "Modbus TCP not connected" : "Modbus TCP 未连接");
return;
}
try
{
UpdateResetButtonStatus(_lang == "en-US" ? "Resetting..." : "正在复位...", Brushes.LightGreen);
await Task.Run(() => _modbusMaster.WriteSingleCoil(0x01, _resetAddress, true));
fc.BtnClickFunctionForNew(Function.ButtonType., _resetAddress);
await Task.Delay(100);
await Task.Run(() => _modbusMaster.WriteSingleCoil(0x01, _resetAddress, false));
fc.BtnClickFunctionForNew(Function.ButtonType., _resetAddress);
UpdateResetButtonStatus(_lang == "en-US" ? "Reset Success" : "复位成功", Brushes.LightGreen);
}
catch (Exception ex)
{
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}");
}
}
/// <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)
{
await WriteCoilWithCheck(_BreathUpAddress, true,
_lang == "en-US" ? "Calibration success" : "校准指令已被设备接收并执行",
_lang == "en-US" ? "Calibration timeout" : "校准执行超时,状态异常",
_lang == "en-US" ? "Calibration executed" : "校准指令执行成功");
}
private async void Button_Click_12(object sender, RoutedEventArgs e)
{
await WriteCoilWithCheck(_BreathDownAddress, true,
_lang == "en-US" ? "Calibration success" : "校准指令已被设备接收并执行",
_lang == "en-US" ? "Calibration timeout" : "校准执行超时,状态异常",
_lang == "en-US" ? "Calibration executed" : "校准指令执行成功");
}
private async void Button_Click_13(object sender, RoutedEventArgs e)
{
await WriteCoilWithCheck(_PressCheckAddress, true,
_lang == "en-US" ? "Calibration success" : "校准指令已被设备接收并执行",
_lang == "en-US" ? "Calibration timeout" : "校准执行超时,状态异常",
_lang == "en-US" ? "Calibration executed" : "校准指令执行成功");
}
/// <summary>
/// 写入线圈并验证状态
/// </summary>
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; }
try
{
await Task.Run(() => _modbusMaster.WriteSingleCoilAsync(0x01, coil, val));
Thread.Sleep(200);
if (err.Contains("Calib") || err.Contains("校准")) await Task.Run(() => _modbusMaster.WriteSingleCoilAsync(0x01, coil, false));
Thread.Sleep(100);
await Task.Delay(500);
bool[] status = await _modbusMaster?.ReadCoilsAsync(0x01, coil, 1);
if (status != null && status[0] == val) { WriteLog(log); ShowSuccess(ok); }
else ShowError(err);
}
catch (Exception ex) { ShowError(_lang == "en-US" ? $"Communication error: {ex.Message}" : $"通信错误: {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}");
}
}
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
{
}
}
}
}