From 9d55347ff381c35ced1e5bd2cb9e455cd5b83cf8 Mon Sep 17 00:00:00 2001 From: "GukSang.Jin" Date: Wed, 3 Jun 2026 15:35:55 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=9B=B4=E6=96=B0112?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/SlipResistanceDeviceService.cs | 260 +++++++++++++----- .../ViewModels/MainWindowViewModel.cs | 168 ++++++++--- .../Views/MainWindow.axaml | 24 +- .../Views/MainWindow.axaml.cs | 90 +----- 4 files changed, 332 insertions(+), 210 deletions(-) diff --git a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Services/SlipResistanceDeviceService.cs b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Services/SlipResistanceDeviceService.cs index da49219..a3e83e2 100644 --- a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Services/SlipResistanceDeviceService.cs +++ b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Services/SlipResistanceDeviceService.cs @@ -3,6 +3,7 @@ using NModbus; using NModbus.IO; using Serilog; using System; +using System.Collections.Generic; using System.Globalization; using System.IO.Ports; using System.Threading; @@ -38,10 +39,13 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services private SerialPort? adcPort; private IModbusSerialMaster? plcMaster; private IModbusSerialMaster? adcMaster; - private DeviceSettings settings = new("0.00", "0.00", "0.30", "0", "0.00", "0", "0.00", "0", "0.00", "COM7", "COM8", 115200); + private DeviceSettings settings = new("0.00", "0.00", "0.30", "0", "0.00", "0", "0.00", "0", "0.00", "COM3", "COM4", 115200); private SlipDeviceSnapshot snapshot = SlipDeviceSnapshot.Offline(); private DateTime lastAdcErrorLoggedAt = DateTime.MinValue; private DateTime lastPlcErrorLoggedAt = DateTime.MinValue; + private DateTime lastAdcDiagnosticLoggedAt = DateTime.MinValue; + private DateTime lastAdcCalibrationWarningLoggedAt = DateTime.MinValue; + private string lastAdcCalibrationWarning = string.Empty; private double verticalLoadN; private double horizontalFrictionN; @@ -71,6 +75,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services public void Start(DeviceSettings deviceSettings) { settings = deviceSettings; + LogAdcCalibrationWarningIfNeeded(); Stop(); try @@ -115,6 +120,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services public void UpdateSettings(DeviceSettings deviceSettings) { settings = deviceSettings; + LogAdcCalibrationWarningIfNeeded(); Log.Debug( "设备设置已更新:PLC={PlcPort}, ADC={AdcPort}, BaudRate={BaudRate}, TestSpeed={TestSpeed}, ManualSpeed={ManualSpeed}, ManualDisplacement={ManualDisplacement}", settings.PlcPortName, @@ -131,57 +137,23 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services public Task PulseResetAsync() => PulseCoilAsync(ResetCoil); - public async Task StartLiftAsync() + public async Task ApplyOldLiftAsync() { await WriteCoilAsync(LowerCoil, false); await WriteCoilAsync(LiftCoil, true); - Log.Information("提升按下运行:M{LiftCoil}=1, M{LowerCoil}=0", LiftCoil, LowerCoil); + Log.Information("提升按钮按老代码执行:M{LowerCoil}=0, M{LiftCoil}=1", LowerCoil, LiftCoil); } - public async Task StopLiftAsync() - { - await WriteCoilAsync(LiftCoil, false); - Log.Information("提升松开停止:M{LiftCoil}=0", LiftCoil); - } - - public async Task StartLowerAsync() + public async Task ApplyOldLowerAsync() { await WriteCoilAsync(LiftCoil, false); await WriteCoilAsync(LowerCoil, true); - Log.Information("下降按下运行:M{LowerCoil}=1, M{LiftCoil}=0", LowerCoil, LiftCoil); + Log.Information("下降按钮按老代码执行:M{LiftCoil}=0, M{LowerCoil}=1", LiftCoil, LowerCoil); } - public async Task StopLowerAsync() - { - await WriteCoilAsync(LowerCoil, false); - Log.Information("下降松开停止:M{LowerCoil}=0", LowerCoil); - } + public Task ToggleOldMoveLeftAsync() => ToggleCoilAsync(MoveLeftCoil); - public async Task StartMoveLeftAsync() - { - await WriteCoilAsync(MoveRightCoil, false); - await WriteCoilAsync(MoveLeftCoil, true); - Log.Information("左移按下运行:M{MoveLeftCoil}=1, M{MoveRightCoil}=0", MoveLeftCoil, MoveRightCoil); - } - - public async Task StopMoveLeftAsync() - { - await WriteCoilAsync(MoveLeftCoil, false); - Log.Information("左移松开停止:M{MoveLeftCoil}=0", MoveLeftCoil); - } - - public async Task StartMoveRightAsync() - { - await WriteCoilAsync(MoveLeftCoil, false); - await WriteCoilAsync(MoveRightCoil, true); - Log.Information("右移按下运行:M{MoveRightCoil}=1, M{MoveLeftCoil}=0", MoveRightCoil, MoveLeftCoil); - } - - public async Task StopMoveRightAsync() - { - await WriteCoilAsync(MoveRightCoil, false); - Log.Information("右移松开停止:M{MoveRightCoil}=0", MoveRightCoil); - } + public Task ToggleOldMoveRightAsync() => ToggleCoilAsync(MoveRightCoil); public async Task StopAllMotionAsync() { @@ -332,13 +304,8 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services var friction1Raw = UshortToInt(data[6], data[7]); var friction2Raw = UshortToInt(data[2], data[3]); - var pressure = ConvertAdc(pressureRaw, settings.NormalPressureZero, settings.NormalPressureCoefficient); - - // Keep the old instrument channel wiring: ADC 6/7 uses zero 1 with coefficient 2, - // and ADC 2/3 uses zero 2 with coefficient 1. - var friction1 = ConvertAdc(friction1Raw, settings.FrictionZero1, settings.FrictionCoefficient2); - var friction2 = ConvertAdc(friction2Raw, settings.FrictionZero2, settings.FrictionCoefficient1); - var friction = (friction1 + friction2) * -1.0; + var conversion = ConvertAdcReadings(pressureRaw, friction1Raw, friction2Raw); + LogAdcDiagnostic(pressureRaw, friction1Raw, friction2Raw, conversion); lock (sync) { @@ -346,14 +313,25 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services frictionRawValue1 = friction1Raw; frictionRawValue2 = friction2Raw; hasAdcRawValues = true; - verticalLoadN = pressure; - horizontalFrictionN = friction; - adcLastError = string.Empty; - isAdcConnected = true; + if (conversion.IsValid) + { + verticalLoadN = conversion.Pressure; + horizontalFrictionN = conversion.Friction; + adcLastError = string.Empty; + isAdcConnected = true; + } + else + { + verticalLoadN = 0; + horizontalFrictionN = 0; + adcLastError = conversion.Error; + isAdcConnected = false; + } + RefreshSnapshotLocked(); } - Thread.Sleep(10); + Thread.Sleep(conversion.IsValid ? 10 : 100); } catch (Exception ex) { @@ -405,13 +383,19 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services } } - private async Task PulseCoilAsync(ushort coil) - { - Log.Information("发送 PLC 脉冲线圈:M{Coil}", coil); - await WriteCoilAsync(coil, true); - await Task.Delay(80); - await WriteCoilAsync(coil, false); - } + private Task PulseCoilAsync(ushort coil) => + Task.Run(() => + { + lock (plcIoLock) + { + var master = plcMaster ?? throw new InvalidOperationException("PLC 未连接"); + Log.Information("按老代码逻辑发送 PLC 脉冲线圈:M{Coil}=true -> false", coil); + master.WriteSingleCoil(SlaveId, coil, true); + Log.Debug("写入 PLC 线圈:M{Coil}=true", coil); + master.WriteSingleCoil(SlaveId, coil, false); + Log.Debug("写入 PLC 线圈:M{Coil}=false", coil); + } + }); private Task ToggleCoilAsync(ushort coil) => Task.Run(() => @@ -532,24 +516,141 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services error); } - private static double ConvertAdc(int rawValue, string zeroText, string coefficientText) + private AdcConversionResult ConvertAdcReadings(int pressureRaw, int friction1Raw, int friction2Raw) { - var zero = ParseDouble(zeroText); - var coefficient = ParseDouble(coefficientText); - if (Math.Abs(coefficient) < 0.0001) + if (!ValidateAdcSettings(out var pressureZero, out var pressureCoefficient, out var frictionZero1, out var frictionCoefficient1, out var frictionZero2, out var frictionCoefficient2, out var error)) { - return 0; + return AdcConversionResult.Invalid(error); } - return (rawValue - zero) / coefficient; + var pressure = ConvertAdc(pressureRaw, pressureZero, pressureCoefficient); + + // Keep the old instrument channel wiring: ADC 6/7 uses zero 1 with coefficient 2, + // and ADC 2/3 uses zero 2 with coefficient 1. + var friction1 = ConvertAdc(friction1Raw, frictionZero1, frictionCoefficient2); + var friction2 = ConvertAdc(friction2Raw, frictionZero2, frictionCoefficient1); + var friction = (friction1 + friction2) * -1.0; + return AdcConversionResult.Valid(pressure, friction1, friction2, friction); } - private static double ParseDouble(string value) => - double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var invariantValue) - ? invariantValue - : double.TryParse(value, NumberStyles.Float, CultureInfo.CurrentCulture, out var localValue) - ? localValue - : 0; + private bool ValidateAdcSettings( + out double pressureZero, + out double pressureCoefficient, + out double frictionZero1, + out double frictionCoefficient1, + out double frictionZero2, + out double frictionCoefficient2, + out string error) + { + var invalid = new List(); + TryParseSetting(settings.NormalPressureZero, "正压力零点", false, invalid, out pressureZero); + TryParseSetting(settings.NormalPressureCoefficient, "正压力校准系数", true, invalid, out pressureCoefficient); + TryParseSetting(settings.FrictionZero1, "摩擦1零点", false, invalid, out frictionZero1); + TryParseSetting(settings.FrictionCoefficient1, "摩擦1校准系数", true, invalid, out frictionCoefficient1); + TryParseSetting(settings.FrictionZero2, "摩擦2零点", false, invalid, out frictionZero2); + TryParseSetting(settings.FrictionCoefficient2, "摩擦2校准系数", true, invalid, out frictionCoefficient2); + + if (invalid.Count == 0) + { + error = string.Empty; + return true; + } + + error = "ADC 校准参数无效:" + string.Join("、", invalid) + ";请填写旧机实际标定值后再测试"; + return false; + } + + private void LogAdcCalibrationWarningIfNeeded() + { + if (!ValidateAdcSettings(out _, out _, out _, out _, out _, out _, out var error)) + { + var now = DateTime.UtcNow; + if (error == lastAdcCalibrationWarning && now - lastAdcCalibrationWarningLoggedAt < TimeSpan.FromSeconds(5)) + { + return; + } + + lastAdcCalibrationWarning = error; + lastAdcCalibrationWarningLoggedAt = now; + Log.Warning( + "{Error}. CurrentSettings: NormalPressureZero={NormalPressureZero}, NormalPressureCoefficient={NormalPressureCoefficient}, FrictionZero1={FrictionZero1}, FrictionCoefficient1={FrictionCoefficient1}, FrictionZero2={FrictionZero2}, FrictionCoefficient2={FrictionCoefficient2}", + error, + settings.NormalPressureZero, + settings.NormalPressureCoefficient, + settings.FrictionZero1, + settings.FrictionCoefficient1, + settings.FrictionZero2, + settings.FrictionCoefficient2); + return; + } + + lastAdcCalibrationWarning = string.Empty; + } + + private void LogAdcDiagnostic(int pressureRaw, int friction1Raw, int friction2Raw, AdcConversionResult conversion) + { + var now = DateTime.UtcNow; + if (now - lastAdcDiagnosticLoggedAt < TimeSpan.FromSeconds(conversion.IsValid ? 1 : 5)) + { + return; + } + + lastAdcDiagnosticLoggedAt = now; + if (conversion.IsValid) + { + Log.Debug( + "ADC 采样:RawPressure={RawPressure}, RawFriction1={RawFriction1}, RawFriction2={RawFriction2}, Pressure={Pressure:F3} N, Friction1={Friction1:F3} N, Friction2={Friction2:F3} N, Friction={Friction:F3} N, Coefficients=[P:{PressureCoefficient}, F1:{FrictionCoefficient1}, F2:{FrictionCoefficient2}], Zeros=[P:{PressureZero}, F1:{FrictionZero1}, F2:{FrictionZero2}]", + pressureRaw, + friction1Raw, + friction2Raw, + conversion.Pressure, + conversion.Friction1, + conversion.Friction2, + conversion.Friction, + settings.NormalPressureCoefficient, + settings.FrictionCoefficient1, + settings.FrictionCoefficient2, + settings.NormalPressureZero, + settings.FrictionZero1, + settings.FrictionZero2); + } + else + { + Log.Warning( + "ADC 采样无效:{Error}. RawPressure={RawPressure}, RawFriction1={RawFriction1}, RawFriction2={RawFriction2}, Coefficients=[P:{PressureCoefficient}, F1:{FrictionCoefficient1}, F2:{FrictionCoefficient2}], Zeros=[P:{PressureZero}, F1:{FrictionZero1}, F2:{FrictionZero2}]", + conversion.Error, + pressureRaw, + friction1Raw, + friction2Raw, + settings.NormalPressureCoefficient, + settings.FrictionCoefficient1, + settings.FrictionCoefficient2, + settings.NormalPressureZero, + settings.FrictionZero1, + settings.FrictionZero2); + } + } + + private static double ConvertAdc(int rawValue, double zero, double coefficient) => + (rawValue - zero) / coefficient; + + private static void TryParseSetting(string value, string label, bool requireNonZero, List invalid, out double numericValue) + { + if (!TryParseDouble(value, out numericValue)) + { + invalid.Add($"{label}=\"{value}\""); + return; + } + + if (requireNonZero && Math.Abs(numericValue) < 0.0001) + { + invalid.Add($"{label}=0"); + } + } + + private static bool TryParseDouble(string value, out double numericValue) => + double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out numericValue) + || double.TryParse(value, NumberStyles.Float, CultureInfo.CurrentCulture, out numericValue); private static int UshortToInt(ushort first, ushort second) { @@ -605,5 +706,20 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services { } } + + private readonly record struct AdcConversionResult( + bool IsValid, + double Pressure, + double Friction1, + double Friction2, + double Friction, + string Error) + { + public static AdcConversionResult Valid(double pressure, double friction1, double friction2, double friction) => + new(true, pressure, friction1, friction2, friction, string.Empty); + + public static AdcConversionResult Invalid(string error) => + new(false, 0, 0, 0, 0, error); + } } } diff --git a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/ViewModels/MainWindowViewModel.cs b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/ViewModels/MainWindowViewModel.cs index bb8a669..e2ea720 100644 --- a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/ViewModels/MainWindowViewModel.cs +++ b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/ViewModels/MainWindowViewModel.cs @@ -28,6 +28,10 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel private const double DynamicWindowEndSeconds = 0.6; private const int MinimumDynamicWindowPointCount = 10; private const int StandardTrialCount = 3; + private const string DefaultPlcPortName = "COM3"; + private const string DefaultAdcPortName = "COM4"; + private const string LegacyPlcPortName = "COM7"; + private const string LegacyAdcPortName = "COM8"; private readonly SlipResistanceDeviceService deviceService = new(); private readonly SlipExcelExportService excelExportService = new(); @@ -41,6 +45,9 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel private bool isLoadingDeviceSettings; private bool wasRunning; + private string activePlcPortName = string.Empty; + private string activeAdcPortName = string.Empty; + private int activeBaudRate; private List lastCompletedRun = []; [ObservableProperty] @@ -101,10 +108,10 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel private string frictionCoefficient2 = "0.00"; [ObservableProperty] - private string plcPortName = "COM7"; + private string plcPortName = DefaultPlcPortName; [ObservableProperty] - private string adcPortName = "COM8"; + private string adcPortName = DefaultAdcPortName; [ObservableProperty] private int baudRate = 115200; @@ -136,6 +143,12 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel [ObservableProperty] private string resultSummary = "等待 3 次有效试验"; + [ObservableProperty] + private string testButtonText = "测试"; + + [ObservableProperty] + private string resetButtonText = "复位"; + [ObservableProperty] private string staticCoefficient = "0.00"; @@ -233,7 +246,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel LoadDeviceSettings(); UpdateTargetLoad(); - deviceService.Start(CurrentSettings()); + RestartDeviceConnection(); _ = LoadPlcParametersAsync(); refreshTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(20) }; @@ -244,7 +257,8 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel [RelayCommand] private async Task Clear() { - await RunDeviceCommand(deviceService.PulseResetAsync(), "已发送复位指令 M90"); + ApplyConnectionSettings(); + await RunDeviceCommand(deviceService.PulseResetAsync(), "已按老代码逻辑发送复位指令 M90"); } [RelayCommand] @@ -256,8 +270,20 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel [RelayCommand] private async Task StartTest() { - BeginRun(); - await RunDeviceCommand(deviceService.PulseStartTestAsync(), "已发送测试启动指令 M80,等待 M81 运行状态"); + ApplyConnectionSettings(); + var device = deviceService.CurrentSnapshot; + if (device.IsTestRunning) + { + await RunDeviceCommand(deviceService.PulseStopTestAsync(), "已按老代码逻辑发送停止指令 M83"); + return; + } + + if (!ValidateAdcCoefficientsBeforeTest()) + { + return; + } + + await RunDeviceCommand(deviceService.PulseStartTestAsync(), "已按老代码逻辑发送测试启动指令 M80,等待 M81 运行状态"); } [RelayCommand] @@ -307,21 +333,17 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel } } - public Task StartLiftMotionAsync() => RunDeviceCommand(deviceService.StartLiftAsync(), "垂直架提升中,松开停止"); + [RelayCommand] + private Task LiftMotion() => RunDeviceCommand(deviceService.ApplyOldLiftAsync(), "提升按老代码逻辑执行:M4=0, M5=1"); - public Task StopLiftMotionAsync() => RunDeviceCommand(deviceService.StopLiftAsync(), "垂直架提升已停止"); + [RelayCommand] + private Task LowerMotion() => RunDeviceCommand(deviceService.ApplyOldLowerAsync(), "下降按老代码逻辑执行:M5=0, M4=1"); - public Task StartLowerMotionAsync() => RunDeviceCommand(deviceService.StartLowerAsync(), "垂直架下降中,松开停止"); + [RelayCommand] + private Task MoveLeftMotion() => RunDeviceCommand(deviceService.ToggleOldMoveLeftAsync(), "左移按老代码逻辑切换 M1"); - public Task StopLowerMotionAsync() => RunDeviceCommand(deviceService.StopLowerAsync(), "垂直架下降已停止"); - - public Task StartMoveLeftMotionAsync() => RunDeviceCommand(deviceService.StartMoveLeftAsync(), "水平板左移中,松开停止"); - - public Task StopMoveLeftMotionAsync() => RunDeviceCommand(deviceService.StopMoveLeftAsync(), "水平板左移已停止"); - - public Task StartMoveRightMotionAsync() => RunDeviceCommand(deviceService.StartMoveRightAsync(), "水平板右移中,松开停止"); - - public Task StopMoveRightMotionAsync() => RunDeviceCommand(deviceService.StopMoveRightAsync(), "水平板右移已停止"); + [RelayCommand] + private Task MoveRightMotion() => RunDeviceCommand(deviceService.ToggleOldMoveRightAsync(), "右移按老代码逻辑切换 M2"); public Task StopAllMotionAsync() => RunDeviceCommand(deviceService.StopAllMotionAsync(), "全部运动已停止"); @@ -350,7 +372,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel private void CloseSettingsDialog() { IsSettingsDialogOpen = false; - deviceService.UpdateSettings(CurrentSettings()); + ApplyConnectionSettings(); } [RelayCommand] @@ -452,19 +474,34 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel private void RefreshFromDevice() { var device = deviceService.CurrentSnapshot; - DeviceStatus = device.IsConnected - ? device.IsTestRunning ? "联机 / 测试中" : device.IsResetting ? "联机 / 复位中" : "联机 / 待机" - : "离线"; - - VerticalPressure = device.VerticalLoadN.ToString("F1", CultureInfo.InvariantCulture); - HorizontalForce = device.HorizontalFrictionN.ToString("F1", CultureInfo.InvariantCulture); - FrictionCoefficient = device.FrictionCoefficient.ToString("F3", CultureInfo.InvariantCulture); - Distance = device.DisplacementMm.ToString("F1", CultureInfo.InvariantCulture); - ActualLoadText = $"{VerticalPressure} N"; + if (device.IsConnected) + { + DeviceStatus = device.IsTestRunning ? "联机 / 测试中" : device.IsResetting ? "联机 / 复位中" : "联机 / 待机"; + TestButtonText = device.IsTestRunning ? "停止" : "测试"; + ResetButtonText = device.IsResetting ? "复位中" : "复位"; + VerticalPressure = device.VerticalLoadN.ToString("F1", CultureInfo.InvariantCulture); + HorizontalForce = device.HorizontalFrictionN.ToString("F1", CultureInfo.InvariantCulture); + FrictionCoefficient = device.FrictionCoefficient.ToString("F3", CultureInfo.InvariantCulture); + Distance = device.DisplacementMm.ToString("F1", CultureInfo.InvariantCulture); + ActualLoadText = $"{VerticalPressure} N"; + } + else + { + DeviceStatus = IsAdcCalibrationError(device.LastError) ? "数据无效" : "离线"; + TestButtonText = device.IsTestRunning ? "停止" : "测试"; + ResetButtonText = device.IsResetting ? "复位中" : "复位"; + VerticalPressure = "--"; + HorizontalForce = "--"; + FrictionCoefficient = "--"; + Distance = "--"; + ActualLoadText = "-- N"; + } if (!device.IsConnected && !string.IsNullOrWhiteSpace(device.LastError)) { - CurrentStatus = $"设备离线:{device.LastError}"; + CurrentStatus = IsAdcCalibrationError(device.LastError) + ? $"数据无效:{device.LastError}" + : $"设备离线:{device.LastError}"; } var isRecording = device.IsConnected && device.IsTestRunning; @@ -694,6 +731,54 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel deviceService.UpdateSettings(CurrentSettings()); } + private void ApplyConnectionSettings() + { + var settings = CurrentSettings(); + if (ConnectionSettingsChanged(settings)) + { + RestartDeviceConnection(settings); + return; + } + + deviceService.UpdateSettings(settings); + } + + private bool ConnectionSettingsChanged(DeviceSettings settings) => + !string.Equals(activePlcPortName, settings.PlcPortName, StringComparison.OrdinalIgnoreCase) + || !string.Equals(activeAdcPortName, settings.AdcPortName, StringComparison.OrdinalIgnoreCase) + || activeBaudRate != settings.BaudRate; + + private void RestartDeviceConnection() + { + RestartDeviceConnection(CurrentSettings()); + } + + private void RestartDeviceConnection(DeviceSettings settings) + { + deviceService.Start(settings); + activePlcPortName = settings.PlcPortName; + activeAdcPortName = settings.AdcPortName; + activeBaudRate = settings.BaudRate; + } + + private bool ValidateAdcCoefficientsBeforeTest() + { + var invalid = new List(); + AddInvalidCoefficient(NormalPressureCoefficient, "正压力校准系数", invalid); + AddInvalidCoefficient(FrictionCoefficient1, "摩擦1校准系数", invalid); + AddInvalidCoefficient(FrictionCoefficient2, "摩擦2校准系数", invalid); + + if (invalid.Count == 0) + { + return true; + } + + var message = "ADC 校准系数无效:" + string.Join("、", invalid) + ";请填写旧机实际标定系数后再开始测试"; + Log.Warning("阻止测试启动:{Message}", message); + CurrentStatus = message; + return false; + } + private async Task LoadPlcParametersAsync() { try @@ -739,8 +824,8 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel FrictionCoefficient1 = settings.FrictionCoefficient1 ?? FrictionCoefficient1; FrictionZero2 = settings.FrictionZero2 ?? FrictionZero2; FrictionCoefficient2 = settings.FrictionCoefficient2 ?? FrictionCoefficient2; - PlcPortName = settings.PlcPortName ?? PlcPortName; - AdcPortName = settings.AdcPortName ?? AdcPortName; + PlcPortName = NormalizeSavedPort(settings.PlcPortName, DefaultPlcPortName, LegacyPlcPortName); + AdcPortName = NormalizeSavedPort(settings.AdcPortName, DefaultAdcPortName, LegacyAdcPortName); BaudRate = settings.BaudRate > 0 ? settings.BaudRate : BaudRate; } catch (Exception ex) @@ -831,6 +916,27 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out numericValue) || double.TryParse(value, NumberStyles.Float, CultureInfo.CurrentCulture, out numericValue); + private static void AddInvalidCoefficient(string value, string label, List invalid) + { + if (!TryParseDouble(value, out var coefficient) || Math.Abs(coefficient) < 0.0001) + { + invalid.Add($"{label}={value}"); + } + } + + private static bool IsAdcCalibrationError(string error) => + error.Contains("ADC 校准参数无效", StringComparison.Ordinal); + + private static string NormalizeSavedPort(string? savedPort, string defaultPort, string legacyPort) + { + if (string.IsNullOrWhiteSpace(savedPort) || string.Equals(savedPort, legacyPort, StringComparison.OrdinalIgnoreCase)) + { + return defaultPort; + } + + return savedPort; + } + private static LineSeries CreateLineSeries( string name, ObservableCollection values, diff --git a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Views/MainWindow.axaml b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Views/MainWindow.axaml index d3ce955..f94c829 100644 --- a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Views/MainWindow.axaml +++ b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Views/MainWindow.axaml @@ -325,8 +325,8 @@ -