2026-04-01 20:29:45 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Windows;
|
|
|
|
|
|
using System.Windows.Controls;
|
|
|
|
|
|
using System.Windows.Threading;
|
|
|
|
|
|
using MembranePoreTester.Communication;
|
2026-03-25 21:34:41 +08:00
|
|
|
|
|
|
|
|
|
|
namespace MembranePoreTester
|
|
|
|
|
|
{
|
2026-04-01 20:33:23 +08:00
|
|
|
|
public partial class ParameterWindow : Window
|
2026-03-25 21:34:41 +08:00
|
|
|
|
{
|
2026-04-01 20:29:45 +08:00
|
|
|
|
private readonly IPlcService _plcService;
|
|
|
|
|
|
private readonly PlcConfiguration _config;
|
|
|
|
|
|
private DispatcherTimer _autoRefreshTimer;
|
|
|
|
|
|
|
|
|
|
|
|
// 文本框映射:(文本框, 地址, 参数名, 是否浮点数)
|
|
|
|
|
|
private readonly List<(TextBox textBox, ushort address, string name, bool isFloat)> _textBoxMapping = new();
|
|
|
|
|
|
|
2026-04-01 20:33:23 +08:00
|
|
|
|
public ParameterWindow()
|
2026-03-25 21:34:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
InitializeComponent();
|
2026-04-01 20:29:45 +08:00
|
|
|
|
_plcService = App.PlcService;
|
|
|
|
|
|
_config = App.PlcConfig;
|
|
|
|
|
|
|
|
|
|
|
|
// 16位整数(灯条、中灯、电机)
|
|
|
|
|
|
AddMapping(txtUpperLampData1, _config.UpperLampData1, "上灯条数据1", false);
|
|
|
|
|
|
AddMapping(txtLowerLampData1, _config.LowerLampData1, "下灯条数据1", false);
|
|
|
|
|
|
AddMapping(txtUpperLampData2, _config.UpperLampData2, "上灯条数据2", false);
|
|
|
|
|
|
AddMapping(txtLowerLampData2, _config.LowerLampData2, "下灯条数据2", false);
|
|
|
|
|
|
AddMapping(txtUpperLampData3, _config.UpperLampData3, "上灯条数据3", false);
|
|
|
|
|
|
AddMapping(txtLowerLampData3, _config.LowerLampData3, "下灯条数据3", false);
|
|
|
|
|
|
AddMapping(txtUpperLampData4, _config.UpperLampData4, "上灯条数据4", false);
|
|
|
|
|
|
AddMapping(txtLowerLampData4, _config.LowerLampData4, "下灯条数据4", false);
|
|
|
|
|
|
AddMapping(txtUpperLampData5, _config.UpperLampData5, "上灯条数据5", false);
|
|
|
|
|
|
AddMapping(txtLowerLampData5, _config.LowerLampData5, "下灯条数据5", false);
|
|
|
|
|
|
AddMapping(txtUpperLampData6, _config.UpperLampData6, "上灯条数据6", false);
|
|
|
|
|
|
AddMapping(txtLowerLampData6, _config.LowerLampData6, "下灯条数据6", false);
|
|
|
|
|
|
|
|
|
|
|
|
AddMapping(txtMiddleLamp1, _config.MiddleLamp1, "中灯1", false);
|
|
|
|
|
|
AddMapping(txtMiddleLamp2, _config.MiddleLamp2, "中灯2", false);
|
|
|
|
|
|
AddMapping(txtMiddleLamp3, _config.MiddleLamp3, "中灯3", false);
|
|
|
|
|
|
AddMapping(txtMiddleLamp4, _config.MiddleLamp4, "中灯4", false);
|
|
|
|
|
|
AddMapping(txtMiddleLamp5, _config.MiddleLamp5, "中灯5", false);
|
|
|
|
|
|
AddMapping(txtMiddleLamp6, _config.MiddleLamp6, "中灯6", false);
|
|
|
|
|
|
AddMapping(txtMiddleLamp7, _config.MiddleLamp7, "中灯7", false);
|
|
|
|
|
|
|
|
|
|
|
|
AddMapping(txtMotorLimit, _config.MotorLimit, "电机限位", true);
|
|
|
|
|
|
AddMapping(txtResetCompensation, _config.ResetCompensation, "复位补偿", true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AddMapping(txtLeftEyeAreaCoeff, _config.LeftEyeAreaCoeff, "左眼面积系数", true);
|
|
|
|
|
|
AddMapping(txtRightEyeAreaCoeff, _config.RightEyeAreaCoeff, "右眼面积系数", true);
|
|
|
|
|
|
AddMapping(txtSaveRateCorrectionCoeff, _config.SaveRateCorrectionCoeff, "保存率矫正系数", true);
|
|
|
|
|
|
|
|
|
|
|
|
RegisterTextBoxEvents();
|
|
|
|
|
|
|
|
|
|
|
|
Loaded += async (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
_autoRefreshTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
|
|
|
|
|
|
_autoRefreshTimer.Tick += AutoRefreshTimer_Tick;
|
|
|
|
|
|
_autoRefreshTimer.Start();
|
|
|
|
|
|
await LoadAllParameters();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Closed += (s, e) => _autoRefreshTimer?.Stop();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void AddMapping(TextBox textBox, ushort address, string name, bool isFloat)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (textBox != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_textBoxMapping.Add((textBox, address, name, isFloat));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void RegisterTextBoxEvents()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var (tb, addr, name, isFloat) in _textBoxMapping)
|
|
|
|
|
|
{
|
|
|
|
|
|
tb.LostFocus += async (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (float.TryParse(tb.Text, out float value))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isFloat)
|
|
|
|
|
|
await WriteFloatAsync(addr, value);
|
|
|
|
|
|
else
|
|
|
|
|
|
await WriteInt16Async(addr, (ushort)value);
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"{name} 已写入: {value}");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"写入 {name} 失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"请输入有效的数值", "输入错误", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
|
|
|
|
await UpdateSingleParameter(tb, addr, isFloat);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async void AutoRefreshTimer_Tick(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
await Dispatcher.InvokeAsync(async () =>
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var (tb, addr, name, isFloat) in _textBoxMapping)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!tb.IsFocused)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isFloat)
|
|
|
|
|
|
{
|
|
|
|
|
|
float val = await ReadFloatAsync(addr);
|
|
|
|
|
|
tb.Text = val.ToString("F3");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
ushort val = await ReadInt16Async(addr);
|
|
|
|
|
|
tb.Text = val.ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"自动刷新 {name} 失败: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task UpdateSingleParameter(TextBox tb, ushort addr, bool isFloat)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isFloat)
|
|
|
|
|
|
{
|
|
|
|
|
|
float val = await ReadFloatAsync(addr);
|
|
|
|
|
|
tb.Text = val.ToString("F3");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
ushort val = await ReadInt16Async(addr);
|
|
|
|
|
|
tb.Text = val.ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"更新失败: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task LoadAllParameters()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var (tb, addr, name, isFloat) in _textBoxMapping)
|
|
|
|
|
|
{
|
|
|
|
|
|
await UpdateSingleParameter(tb, addr, isFloat);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 16位整数读写
|
|
|
|
|
|
private async Task<ushort> ReadInt16Async(ushort address)
|
|
|
|
|
|
{
|
|
|
|
|
|
var registers = await ((ModbusTcpPlcService)_plcService).ReadHoldingRegistersAsync(address, 1);
|
|
|
|
|
|
return registers[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task WriteInt16Async(ushort address, ushort value)
|
|
|
|
|
|
{
|
|
|
|
|
|
await ((ModbusTcpPlcService)_plcService).WriteSingleRegisterAsync(address, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 32位浮点数读写
|
|
|
|
|
|
private async Task<float> ReadFloatAsync(ushort address)
|
|
|
|
|
|
{
|
|
|
|
|
|
var registers = await ((ModbusTcpPlcService)_plcService).ReadHoldingRegistersAsync(address, 2);
|
|
|
|
|
|
return ((ModbusTcpPlcService)_plcService).UshortToFloat(registers[1], registers[0]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task WriteFloatAsync(ushort address, float value)
|
|
|
|
|
|
{
|
|
|
|
|
|
await ((ModbusTcpPlcService)_plcService).WriteMultipleRegistersAsync(address, value);
|
2026-03-25 21:34:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|