This commit is contained in:
GukSang.Jin
2026-04-27 17:31:39 +08:00
parent aaeecc6176
commit 8b03b0039f

View File

@@ -116,9 +116,11 @@ public sealed class MainViewModel : ObservableObject, IDisposable
private IReadOnlyList<RawSampleRecord> _lastCompletedSamples = Array.Empty<RawSampleRecord>();
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
{