From 8b03b0039fdb70a9d30a9bc44aa0dd6d44c68e94 Mon Sep 17 00:00:00 2001 From: "GukSang.Jin" Date: Mon, 27 Apr 2026 17:31:39 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- COFTester/ViewModels/MainViewModel.cs | 67 +++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/COFTester/ViewModels/MainViewModel.cs b/COFTester/ViewModels/MainViewModel.cs index 5aa6384..794ef01 100644 --- a/COFTester/ViewModels/MainViewModel.cs +++ b/COFTester/ViewModels/MainViewModel.cs @@ -116,9 +116,11 @@ public sealed class MainViewModel : ObservableObject, IDisposable private IReadOnlyList _lastCompletedSamples = Array.Empty(); private bool _isShowingHistoricalRun; private bool _deviceConnectionFailureLogged; + private bool _isInitializingDeviceConnection; private bool _isReadingFrame; private bool _isPlcCommandBusy; private bool _isSyncingRecipeFromPlc; + private bool _activeRunStartedByPlc; private MachineRuntimeState _machineRuntimeState = MachineRuntimeState.Idle; private string _plcCommandSummary = "等待 PLC 控制指令。"; @@ -582,6 +584,13 @@ public sealed class MainViewModel : ObservableObject, IDisposable private async Task InitializeDeviceConnectionAsync() { + if (_isInitializingDeviceConnection) + { + return; + } + + _isInitializingDeviceConnection = true; + try { await _deviceConnectionService.ConnectAsync(); @@ -609,6 +618,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable } catch (Exception ex) { + _deviceConnectionService.Disconnect(); DeviceReconnectCount++; if (!_deviceConnectionFailureLogged) @@ -629,10 +639,19 @@ public sealed class MainViewModel : ObservableObject, IDisposable _deviceReconnectTimer.Start(); } + finally + { + _isInitializingDeviceConnection = false; + } } private async void OnDeviceReconnectTimerTick(object? sender, EventArgs e) { + if (_isInitializingDeviceConnection) + { + return; + } + if (_deviceConnectionService.IsConnected) { _deviceReconnectTimer.Stop(); @@ -642,13 +661,21 @@ public sealed class MainViewModel : ObservableObject, IDisposable await InitializeDeviceConnectionAsync(); } - private void StartOrResume() + private async void StartOrResume() { if (!TryValidateStartOrResume()) { return; } + if (_machineRuntimeState == MachineRuntimeState.Paused && _activeRunStartedByPlc) + { + if (!await ExecutePlcPulseCommandAsync("继续", CoilStart, updateLocalState: false)) + { + return; + } + } + StartOrResumeCore(); } @@ -669,7 +696,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable return false; } - private void StartOrResumeCore() + private void StartOrResumeCore(bool startedByPlc = false) { var isRecoveringActiveRun = _machineRuntimeState == MachineRuntimeState.Interlocked && HasRecoverableActiveRunContext(); @@ -678,6 +705,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable { _activeRunId = Guid.NewGuid(); _activeRecipeSnapshot = TestRecipeSnapshot.FromRecipe(Recipe); + _activeRunStartedByPlc = startedByPlc; _displayedRecipeSnapshot = _activeRecipeSnapshot; _isShowingHistoricalRun = false; _currentRunSamples.Clear(); @@ -711,12 +739,14 @@ public sealed class MainViewModel : ObservableObject, IDisposable } else if (isRecoveringActiveRun) { + _activeRunStartedByPlc |= startedByPlc; _isShowingHistoricalRun = false; _displayedRecipeSnapshot = _activeRecipeSnapshot; AddInfoEvent($"试验通信恢复后继续运行,已保留 {_currentRunSamples.Count} 个采样点。"); } else { + _activeRunStartedByPlc |= startedByPlc; AddInfoEvent("试验继续运行。"); } @@ -728,8 +758,16 @@ public sealed class MainViewModel : ObservableObject, IDisposable RaiseStatusProperties(); } - private void Pause() + private async void Pause() { + if (_activeRunStartedByPlc) + { + if (!await ExecutePlcPulseCommandAsync("暂停", CoilStop, updateLocalState: false)) + { + return; + } + } + _timer.Stop(); _machineRuntimeState = MachineRuntimeState.Paused; MachineState = "暂停"; @@ -783,7 +821,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable if (await ExecutePlcPulseCommandAsync("启动", CoilStart, updateLocalState: false)) { - StartOrResumeCore(); + StartOrResumeCore(startedByPlc: true); } } @@ -932,6 +970,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable _lastCompletedRecipeSnapshot = _activeRecipeSnapshot ?? TestRecipeSnapshot.FromRecipe(Recipe); _lastCompletedSamples = _currentRunSamples.ToArray(); PersistLastCompletedRun(); + ResetActiveRunContext(); SelectedRunRecord = record; NextRunIndex++; UpdateDerivedValues(); @@ -1280,6 +1319,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable { _activeRunId = Guid.Empty; _activeRecipeSnapshot = null; + _activeRunStartedByPlc = false; _currentRunSamples.Clear(); } @@ -1357,12 +1397,19 @@ public sealed class MainViewModel : ObservableObject, IDisposable try { var master = _deviceConnectionService.Master; - Recipe.SledMassGrams = await ReadFloatHoldingRegisterAsync(master, RegisterSledMassGrams); - Recipe.LiftSpeedMmPerMin = await ReadFloatHoldingRegisterAsync(master, RegisterLiftSpeed); - Recipe.LiftDisplacementMm = await ReadFloatHoldingRegisterAsync(master, RegisterLiftDisplacement); - Recipe.SpeedMmPerMin = await ReadFloatHoldingRegisterAsync(master, RegisterHorizontalSpeed); - Recipe.TravelMm = await ReadFloatHoldingRegisterAsync(master, RegisterHorizontalDisplacement); - Recipe.ReplicateCount = Math.Clamp((int)Math.Round(await ReadFloatHoldingRegisterAsync(master, RegisterReplicateCount)), 0, 1); + var sledMassGrams = await ReadFloatHoldingRegisterAsync(master, RegisterSledMassGrams); + var liftSpeedMmPerMin = await ReadFloatHoldingRegisterAsync(master, RegisterLiftSpeed); + var liftDisplacementMm = await ReadFloatHoldingRegisterAsync(master, RegisterLiftDisplacement); + var speedMmPerMin = await ReadFloatHoldingRegisterAsync(master, RegisterHorizontalSpeed); + var travelMm = await ReadFloatHoldingRegisterAsync(master, RegisterHorizontalDisplacement); + var replicateCount = Math.Clamp((int)Math.Round(await ReadFloatHoldingRegisterAsync(master, RegisterReplicateCount)), 0, 1); + + Recipe.SledMassGrams = sledMassGrams; + Recipe.LiftSpeedMmPerMin = liftSpeedMmPerMin; + Recipe.LiftDisplacementMm = liftDisplacementMm; + Recipe.SpeedMmPerMin = speedMmPerMin; + Recipe.TravelMm = travelMm; + Recipe.ReplicateCount = replicateCount; } finally {