diff --git a/DentistryHandpieces/MainWindow.xaml b/DentistryHandpieces/MainWindow.xaml
index 63a02c9..5e3ec02 100644
--- a/DentistryHandpieces/MainWindow.xaml
+++ b/DentistryHandpieces/MainWindow.xaml
@@ -503,7 +503,7 @@
+ Text="{Binding AxialForceSetpointInput, UpdateSourceTrigger=PropertyChanged, Delay=600}" />
+ Text="{Binding AxialForceHoldTimeInput, UpdateSourceTrigger=PropertyChanged, Delay=600}" />
+ Text="{Binding HoldTorqueInput, UpdateSourceTrigger=PropertyChanged, Delay=600}" />
+ Text="{Binding TorqueHoldTimeInput, UpdateSourceTrigger=PropertyChanged, Delay=600}" />
_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()