参数更新

This commit is contained in:
GukSang.Jin
2026-06-09 14:08:04 +08:00
parent 945ff7bc12
commit eb65836601
3 changed files with 266 additions and 78 deletions

View File

@@ -503,7 +503,7 @@
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<TextBox x:Name="AxialForceSetpointInput"
Text="{Binding AxialForceSetpointInput, UpdateSourceTrigger=PropertyChanged}" />
Text="{Binding AxialForceSetpointInput, UpdateSourceTrigger=PropertyChanged, Delay=600}" />
<TextBlock Grid.Column="1"
Text="N"
Style="{StaticResource MutedText}"
@@ -519,7 +519,7 @@
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<TextBox x:Name="AxialForceHoldTimeInput"
Text="{Binding AxialForceHoldTimeInput, UpdateSourceTrigger=PropertyChanged}" />
Text="{Binding AxialForceHoldTimeInput, UpdateSourceTrigger=PropertyChanged, Delay=600}" />
<TextBlock Grid.Column="1"
Text="s"
Style="{StaticResource MutedText}"
@@ -797,7 +797,7 @@
Margin="0,0,12,0" />
<TextBox Grid.Column="1"
x:Name="HoldTorqueInput"
Text="{Binding HoldTorqueInput, UpdateSourceTrigger=PropertyChanged}" TextChanged="HoldTorqueInput_TextChanged" />
Text="{Binding HoldTorqueInput, UpdateSourceTrigger=PropertyChanged, Delay=600}" />
<TextBlock Grid.Column="2"
Text="mN.m"
Style="{StaticResource MutedText}"
@@ -816,7 +816,7 @@
Margin="0,0,12,0" />
<TextBox Grid.Column="1"
x:Name="TorqueHoldTimeInput"
Text="{Binding TorqueHoldTimeInput, UpdateSourceTrigger=PropertyChanged}" />
Text="{Binding TorqueHoldTimeInput, UpdateSourceTrigger=PropertyChanged, Delay=600}" />
<TextBlock Grid.Column="2"
Text="s"
Style="{StaticResource MutedText}"
@@ -999,7 +999,7 @@
Margin="0,16,12,0" />
<TextBox Grid.Row="1"
Grid.Column="1"
Text="{Binding NoLoadSpeedSettingInput, UpdateSourceTrigger=PropertyChanged}"
Text="{Binding NoLoadSpeedSettingInput, UpdateSourceTrigger=PropertyChanged, Delay=600}"
Margin="0,16,12,0" />
<TextBlock Grid.Row="1"
Grid.Column="2"

View File

@@ -118,11 +118,6 @@ public partial class MainWindow : Window
}
}
private void HoldTorqueInput_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
}
private async void ManualMotionButton_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (sender is not Button button)

View File

@@ -22,6 +22,16 @@ internal enum ManualMotionTarget
SpeedTorqueBackward
}
internal enum TestPageInputParameter
{
AxialPullForceSetpoint,
AxialJumpForceSetpoint,
AxialForceHoldTime,
HoldTorque,
TorqueHoldTime,
NoLoadSpeedSetting
}
public sealed class MainWindowViewModel : ObservableObject
{
private const ushort SpeedTorqueBackwardCoil = 0;
@@ -139,6 +149,7 @@ public sealed class MainWindowViewModel : ObservableObject
private readonly DispatcherTimer _realtimeTimer;
private readonly DispatcherTimer _parameterRetryTimer;
private readonly object _snapshotWriteLock = new();
private readonly SemaphoreSlim _testPageInputWriteLock = new(1, 1);
private readonly string _applicationDataDirectory;
private readonly string _recordsDirectory;
private readonly string _parameterConfigPath;
@@ -228,6 +239,9 @@ public sealed class MainWindowViewModel : ObservableObject
private string _dataCaptureStatusText = "完整采样:等待测试启动;自动备份:已启用;导出校验:已启用";
private string _parameterStatusText = "参数配置将保存到本地文件。";
private string _axialForceSetpointInput = "0";
private string _axialForceHoldTimeInput = "0";
private string _holdTorqueInput = "0";
private string _torqueHoldTimeInput = "0";
private string _axialForceSetpointModeButtonText = "轴向跳动力设置";
private string _displacementResetButtonText = "复位";
private string _speedTorqueResetButtonText = "复位";
@@ -387,20 +401,41 @@ public sealed class MainWindowViewModel : ObservableObject
if (!TryReadNonNegative(value, GetActiveAxialForceSetpointName(), out double axialForceSetpoint, out string error))
{
ParameterStatusText = error;
SetTestPageInputStatus(
_parameterConfig.UseAxialPullForceSetpoint ? TestPageInputParameter.AxialPullForceSetpoint : TestPageInputParameter.AxialJumpForceSetpoint,
error);
return;
}
_parameterConfig = WithActiveAxialForceSetpoint(axialForceSetpoint);
SaveParameterConfig();
UpdateParameterSummaries();
_ = AutoStopIfSetpointReachedAsync();
TestPageInputParameter parameter = _parameterConfig.UseAxialPullForceSetpoint
? TestPageInputParameter.AxialPullForceSetpoint
: TestPageInputParameter.AxialJumpForceSetpoint;
ushort registerAddress = _parameterConfig.UseAxialPullForceSetpoint
? AxialPullForceSetpointRegister
: AxialJumpForceSetpointRegister;
_ = WriteFloatTestPageInputAsync(parameter, registerAddress, GetActiveAxialForceSetpointName(), axialForceSetpoint);
}
}
public string AxialForceProtectionInput { get; set; } = "50";
public string AxialForceHoldTimeInput { get; set; } = "0";
public string AxialForceHoldTimeInput
{
get => _axialForceHoldTimeInput;
set
{
if (!SetProperty(ref _axialForceHoldTimeInput, value) || _isApplyingParameterConfigToInputs)
{
return;
}
QueueTenthsTestPageInputWrite(
TestPageInputParameter.AxialForceHoldTime,
AxialForceHoldTimeRegister,
"轴向力保持时间设置",
value);
}
}
public string SpeedTorqueDisplacementLimitInput { get; set; } = "0";
@@ -412,9 +447,33 @@ public sealed class MainWindowViewModel : ObservableObject
public string TorqueProtectionInput { get; set; } = "0";
public string HoldTorqueInput { get; set; } = "0";
public string HoldTorqueInput
{
get => _holdTorqueInput;
set
{
if (!SetProperty(ref _holdTorqueInput, value) || _isApplyingParameterConfigToInputs)
{
return;
}
public string TorqueHoldTimeInput { get; set; } = "0";
QueueTenthsTestPageInputWrite(TestPageInputParameter.HoldTorque, HoldTorqueRegister, "保持扭矩设置", value);
}
}
public string TorqueHoldTimeInput
{
get => _torqueHoldTimeInput;
set
{
if (!SetProperty(ref _torqueHoldTimeInput, value) || _isApplyingParameterConfigToInputs)
{
return;
}
QueueTenthsTestPageInputWrite(TestPageInputParameter.TorqueHoldTime, TorqueHoldTimeRegister, "扭矩保持时间设置", value);
}
}
public string SpeedCoefficientInput { get; set; } = "1";
@@ -425,7 +484,15 @@ public sealed class MainWindowViewModel : ObservableObject
public string NoLoadSpeedSettingInput
{
get => _noLoadSpeedSettingInput;
set => SetProperty(ref _noLoadSpeedSettingInput, value);
set
{
if (!SetProperty(ref _noLoadSpeedSettingInput, value) || _isApplyingParameterConfigToInputs)
{
return;
}
QueueFloatTestPageInputWrite(TestPageInputParameter.NoLoadSpeedSetting, NoLoadSpeedSettingRegister, "空载转速设置", value);
}
}
public string PlcIpAddressInput { get; set; } = "192.168.1.10";
@@ -865,41 +932,6 @@ public sealed class MainWindowViewModel : ObservableObject
return options;
}
private TestParameterConfig WithActiveAxialForceSetpoint(double axialForceSetpoint)
{
return new TestParameterConfig
{
AxialDisplacementLimit = _parameterConfig.AxialDisplacementLimit,
AxialSpeed = _parameterConfig.AxialSpeed,
AxialManualDisplacement = _parameterConfig.AxialManualDisplacement,
AxialForceLowerLimit = _parameterConfig.AxialForceLowerLimit,
AxialForceUpperLimit = _parameterConfig.AxialForceUpperLimit,
AxialForceCoefficient = _parameterConfig.AxialForceCoefficient,
AxialForceSetpoint = _parameterConfig.UseAxialPullForceSetpoint ? axialForceSetpoint : _parameterConfig.AxialForceSetpoint,
AxialJumpForceSetpoint = _parameterConfig.UseAxialPullForceSetpoint ? _parameterConfig.AxialJumpForceSetpoint : axialForceSetpoint,
UseAxialPullForceSetpoint = _parameterConfig.UseAxialPullForceSetpoint,
AxialForceProtection = _parameterConfig.AxialForceProtection,
AxialForceHoldTime = _parameterConfig.AxialForceHoldTime,
SpeedTorqueDisplacementLimit = _parameterConfig.SpeedTorqueDisplacementLimit,
SpeedTorqueSpeed = _parameterConfig.SpeedTorqueSpeed,
SpeedTorqueManualDisplacement = _parameterConfig.SpeedTorqueManualDisplacement,
TorqueCoefficient = _parameterConfig.TorqueCoefficient,
TorqueProtection = _parameterConfig.TorqueProtection,
HoldTorque = _parameterConfig.HoldTorque,
TorqueHoldTime = _parameterConfig.TorqueHoldTime,
SpeedCoefficient = _parameterConfig.SpeedCoefficient,
SpeedStopThreshold = _parameterConfig.SpeedStopThreshold,
PressureCoefficient = _parameterConfig.PressureCoefficient,
NoLoadSpeedSetting = _parameterConfig.NoLoadSpeedSetting,
PlcIpAddress = _parameterConfig.PlcIpAddress,
PlcPort = _parameterConfig.PlcPort,
PlcUnitId = _parameterConfig.PlcUnitId,
PlcPulseMilliseconds = _parameterConfig.PlcPulseMilliseconds,
PlcTimeoutMilliseconds = _parameterConfig.PlcTimeoutMilliseconds,
FloatWordOrder = _parameterConfig.FloatWordOrder
};
}
private TestParameterConfig WithAxialForceSetpointMode(bool usePullForceSetpoint)
{
return new TestParameterConfig
@@ -935,9 +967,9 @@ public sealed class MainWindowViewModel : ObservableObject
};
}
private TestParameterConfig WithNoLoadSpeedSetting(double noLoadSpeedSetting)
private TestParameterConfig WithTestPageInputParameter(TestPageInputParameter parameter, double value)
{
TestParameterConfig config = CloneParameterConfig(_parameterConfig);
TestParameterConfig config = _parameterConfig;
return new TestParameterConfig
{
AxialDisplacementLimit = config.AxialDisplacementLimit,
@@ -946,22 +978,22 @@ public sealed class MainWindowViewModel : ObservableObject
AxialForceLowerLimit = config.AxialForceLowerLimit,
AxialForceUpperLimit = config.AxialForceUpperLimit,
AxialForceCoefficient = config.AxialForceCoefficient,
AxialForceSetpoint = config.AxialForceSetpoint,
AxialJumpForceSetpoint = config.AxialJumpForceSetpoint,
AxialForceSetpoint = parameter == TestPageInputParameter.AxialPullForceSetpoint ? value : config.AxialForceSetpoint,
AxialJumpForceSetpoint = parameter == TestPageInputParameter.AxialJumpForceSetpoint ? value : config.AxialJumpForceSetpoint,
UseAxialPullForceSetpoint = config.UseAxialPullForceSetpoint,
AxialForceProtection = config.AxialForceProtection,
AxialForceHoldTime = config.AxialForceHoldTime,
AxialForceHoldTime = parameter == TestPageInputParameter.AxialForceHoldTime ? value : config.AxialForceHoldTime,
SpeedTorqueDisplacementLimit = config.SpeedTorqueDisplacementLimit,
SpeedTorqueSpeed = config.SpeedTorqueSpeed,
SpeedTorqueManualDisplacement = config.SpeedTorqueManualDisplacement,
TorqueCoefficient = config.TorqueCoefficient,
TorqueProtection = config.TorqueProtection,
HoldTorque = config.HoldTorque,
TorqueHoldTime = config.TorqueHoldTime,
HoldTorque = parameter == TestPageInputParameter.HoldTorque ? value : config.HoldTorque,
TorqueHoldTime = parameter == TestPageInputParameter.TorqueHoldTime ? value : config.TorqueHoldTime,
SpeedCoefficient = config.SpeedCoefficient,
SpeedStopThreshold = config.SpeedStopThreshold,
PressureCoefficient = config.PressureCoefficient,
NoLoadSpeedSetting = noLoadSpeedSetting,
NoLoadSpeedSetting = parameter == TestPageInputParameter.NoLoadSpeedSetting ? value : config.NoLoadSpeedSetting,
PlcIpAddress = config.PlcIpAddress,
PlcPort = config.PlcPort,
PlcUnitId = config.PlcUnitId,
@@ -2023,6 +2055,178 @@ public sealed class MainWindowViewModel : ObservableObject
}
}
private void QueueFloatTestPageInputWrite(TestPageInputParameter parameter, ushort registerAddress, string fieldName, string input)
{
if (string.IsNullOrWhiteSpace(input))
{
return;
}
if (!TryReadNonNegative(input, fieldName, out double value, out string error))
{
SetTestPageInputStatus(parameter, error);
return;
}
_ = WriteFloatTestPageInputAsync(parameter, registerAddress, fieldName, value);
}
private void QueueTenthsTestPageInputWrite(TestPageInputParameter parameter, ushort registerAddress, string fieldName, string input)
{
if (string.IsNullOrWhiteSpace(input))
{
return;
}
if (!TryReadNonNegative(input, fieldName, out double value, out string error)
|| !CanScaleTenthsToPlc(value, fieldName, out error))
{
SetTestPageInputStatus(parameter, error);
return;
}
_ = WriteTenthsTestPageInputAsync(parameter, registerAddress, fieldName, value);
}
private async Task WriteFloatTestPageInputAsync(TestPageInputParameter parameter, ushort registerAddress, string fieldName, double value)
{
await _testPageInputWriteLock.WaitAsync();
try
{
PlcConnectionConfig config = _parameterConfig.ToPlcConnectionConfig();
await _plcRegisterService.WriteFloatAsync(config, registerAddress, (float)value);
float confirmedValue = await _plcRegisterService.ReadFloatAsync(config, registerAddress);
if (float.IsNaN(confirmedValue) || float.IsInfinity(confirmedValue))
{
throw new InvalidOperationException($"{fieldName} D{registerAddress} 回读无效。");
}
await ApplyConfirmedTestPageInputAsync(parameter, fieldName, registerAddress, value, confirmedValue);
}
catch (Exception ex)
{
SetTestPageInputStatus(parameter, $"{fieldName}自动写入 D{registerAddress} 失败:{ex.Message}");
Log.Error(ex, "{FieldName}自动写入失败D{RegisterAddress}={Value}", fieldName, registerAddress, value);
}
finally
{
_testPageInputWriteLock.Release();
}
}
private async Task WriteTenthsTestPageInputAsync(TestPageInputParameter parameter, ushort registerAddress, string fieldName, double value)
{
await _testPageInputWriteLock.WaitAsync();
try
{
ushort rawValue = ScaleTenthsToPlc(value, fieldName);
PlcConnectionConfig config = _parameterConfig.ToPlcConnectionConfig();
await _plcRegisterService.WriteUInt16Async(config, registerAddress, rawValue);
ushort confirmedRawValue = await _plcRegisterService.ReadUInt16Async(config, registerAddress);
double confirmedValue = ScaleTenthsFromPlc(confirmedRawValue);
await ApplyConfirmedTestPageInputAsync(parameter, fieldName, registerAddress, value, confirmedValue);
}
catch (Exception ex)
{
SetTestPageInputStatus(parameter, $"{fieldName}自动写入 D{registerAddress} 失败:{ex.Message}");
Log.Error(ex, "{FieldName}自动写入失败D{RegisterAddress}={Value}", fieldName, registerAddress, value);
}
finally
{
_testPageInputWriteLock.Release();
}
}
private async Task ApplyConfirmedTestPageInputAsync(
TestPageInputParameter parameter,
string fieldName,
ushort registerAddress,
double requestedValue,
double confirmedValue)
{
_parameterConfig = WithTestPageInputParameter(parameter, confirmedValue);
SaveParameterConfig();
UpdateParameterSummaries();
ApplyConfirmedTestPageInputToEditor(parameter, requestedValue, confirmedValue);
if (parameter is TestPageInputParameter.HoldTorque or TestPageInputParameter.TorqueHoldTime)
{
_cachedTorqueCurve = null;
UpdateTorqueCurveStatus();
}
SetTestPageInputStatus(parameter, $"{fieldName}已自动写入并回读确认 D{registerAddress}={FormatConfigNumber(confirmedValue)}");
Log.Information("{FieldName}自动写入并回读成功D{RegisterAddress}={Value}", fieldName, registerAddress, confirmedValue);
if (parameter is TestPageInputParameter.AxialPullForceSetpoint or TestPageInputParameter.AxialJumpForceSetpoint)
{
await AutoStopIfSetpointReachedAsync();
}
}
private void ApplyConfirmedTestPageInputToEditor(TestPageInputParameter parameter, double requestedValue, double confirmedValue)
{
string? currentInput = parameter switch
{
TestPageInputParameter.AxialPullForceSetpoint when _parameterConfig.UseAxialPullForceSetpoint => AxialForceSetpointInput,
TestPageInputParameter.AxialJumpForceSetpoint when !_parameterConfig.UseAxialPullForceSetpoint => AxialForceSetpointInput,
TestPageInputParameter.AxialForceHoldTime => AxialForceHoldTimeInput,
TestPageInputParameter.HoldTorque => HoldTorqueInput,
TestPageInputParameter.TorqueHoldTime => TorqueHoldTimeInput,
TestPageInputParameter.NoLoadSpeedSetting => NoLoadSpeedSettingInput,
_ => null
};
if (currentInput is null
|| !TryReadNumber(currentInput, "自动写入输入", out double currentValue, out _)
|| Math.Abs(currentValue - requestedValue) > 0.000001)
{
return;
}
_isApplyingParameterConfigToInputs = true;
try
{
string confirmedText = FormatConfigNumber(confirmedValue);
switch (parameter)
{
case TestPageInputParameter.AxialPullForceSetpoint:
case TestPageInputParameter.AxialJumpForceSetpoint:
AxialForceSetpointInput = confirmedText;
break;
case TestPageInputParameter.AxialForceHoldTime:
AxialForceHoldTimeInput = confirmedText;
break;
case TestPageInputParameter.HoldTorque:
HoldTorqueInput = confirmedText;
break;
case TestPageInputParameter.TorqueHoldTime:
TorqueHoldTimeInput = confirmedText;
break;
case TestPageInputParameter.NoLoadSpeedSetting:
NoLoadSpeedSettingInput = confirmedText;
break;
}
}
finally
{
_isApplyingParameterConfigToInputs = false;
}
}
private void SetTestPageInputStatus(TestPageInputParameter parameter, string message)
{
ParameterStatusText = message;
if (parameter == TestPageInputParameter.NoLoadSpeedSetting)
{
NoLoadSpeedStatusText = $"状态:{message}";
}
else
{
StatusText = message;
}
}
private async Task SaveNoLoadSpeedSettingAsync()
{
if (!TryReadNonNegative(NoLoadSpeedSettingInput, "空载转速设置", out double setting, out string error))
@@ -2032,22 +2236,11 @@ public sealed class MainWindowViewModel : ObservableObject
return;
}
try
{
PlcConnectionConfig config = _parameterConfig.ToPlcConnectionConfig();
await _plcRegisterService.WriteFloatAsync(config, NoLoadSpeedSettingRegister, (float)setting);
float confirmedSetting = await _plcRegisterService.ReadFloatAsync(config, NoLoadSpeedSettingRegister);
_parameterConfig = WithNoLoadSpeedSetting(confirmedSetting);
SaveParameterConfig();
NoLoadSpeedSettingInput = FormatConfigNumber(confirmedSetting);
NoLoadSpeedStatusText = $"状态:空载转速设置已写入 D{NoLoadSpeedSettingRegister}";
Log.Information("空载转速设置写入并回读成功D{RegisterAddress}={Value}", NoLoadSpeedSettingRegister, confirmedSetting);
}
catch (Exception ex)
{
NoLoadSpeedStatusText = $"状态:空载转速设置写入失败:{ex.Message}";
Log.Error(ex, "空载转速设置写入失败D{RegisterAddress}={Value}", NoLoadSpeedSettingRegister, setting);
}
await WriteFloatTestPageInputAsync(
TestPageInputParameter.NoLoadSpeedSetting,
NoLoadSpeedSettingRegister,
"空载转速设置",
setting);
}
private async Task RecordNoLoadSpeedAsync()