更新
This commit is contained in:
@@ -116,9 +116,11 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
private IReadOnlyList<RawSampleRecord> _lastCompletedSamples = Array.Empty<RawSampleRecord>();
|
private IReadOnlyList<RawSampleRecord> _lastCompletedSamples = Array.Empty<RawSampleRecord>();
|
||||||
private bool _isShowingHistoricalRun;
|
private bool _isShowingHistoricalRun;
|
||||||
private bool _deviceConnectionFailureLogged;
|
private bool _deviceConnectionFailureLogged;
|
||||||
|
private bool _isInitializingDeviceConnection;
|
||||||
private bool _isReadingFrame;
|
private bool _isReadingFrame;
|
||||||
private bool _isPlcCommandBusy;
|
private bool _isPlcCommandBusy;
|
||||||
private bool _isSyncingRecipeFromPlc;
|
private bool _isSyncingRecipeFromPlc;
|
||||||
|
private bool _activeRunStartedByPlc;
|
||||||
private MachineRuntimeState _machineRuntimeState = MachineRuntimeState.Idle;
|
private MachineRuntimeState _machineRuntimeState = MachineRuntimeState.Idle;
|
||||||
private string _plcCommandSummary = "等待 PLC 控制指令。";
|
private string _plcCommandSummary = "等待 PLC 控制指令。";
|
||||||
|
|
||||||
@@ -582,6 +584,13 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
|
|
||||||
private async Task InitializeDeviceConnectionAsync()
|
private async Task InitializeDeviceConnectionAsync()
|
||||||
{
|
{
|
||||||
|
if (_isInitializingDeviceConnection)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isInitializingDeviceConnection = true;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _deviceConnectionService.ConnectAsync();
|
await _deviceConnectionService.ConnectAsync();
|
||||||
@@ -609,6 +618,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
_deviceConnectionService.Disconnect();
|
||||||
DeviceReconnectCount++;
|
DeviceReconnectCount++;
|
||||||
|
|
||||||
if (!_deviceConnectionFailureLogged)
|
if (!_deviceConnectionFailureLogged)
|
||||||
@@ -629,10 +639,19 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
|
|
||||||
_deviceReconnectTimer.Start();
|
_deviceReconnectTimer.Start();
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isInitializingDeviceConnection = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnDeviceReconnectTimerTick(object? sender, EventArgs e)
|
private async void OnDeviceReconnectTimerTick(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (_isInitializingDeviceConnection)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_deviceConnectionService.IsConnected)
|
if (_deviceConnectionService.IsConnected)
|
||||||
{
|
{
|
||||||
_deviceReconnectTimer.Stop();
|
_deviceReconnectTimer.Stop();
|
||||||
@@ -642,13 +661,21 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
await InitializeDeviceConnectionAsync();
|
await InitializeDeviceConnectionAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartOrResume()
|
private async void StartOrResume()
|
||||||
{
|
{
|
||||||
if (!TryValidateStartOrResume())
|
if (!TryValidateStartOrResume())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_machineRuntimeState == MachineRuntimeState.Paused && _activeRunStartedByPlc)
|
||||||
|
{
|
||||||
|
if (!await ExecutePlcPulseCommandAsync("继续", CoilStart, updateLocalState: false))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StartOrResumeCore();
|
StartOrResumeCore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -669,7 +696,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartOrResumeCore()
|
private void StartOrResumeCore(bool startedByPlc = false)
|
||||||
{
|
{
|
||||||
var isRecoveringActiveRun = _machineRuntimeState == MachineRuntimeState.Interlocked && HasRecoverableActiveRunContext();
|
var isRecoveringActiveRun = _machineRuntimeState == MachineRuntimeState.Interlocked && HasRecoverableActiveRunContext();
|
||||||
|
|
||||||
@@ -678,6 +705,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
{
|
{
|
||||||
_activeRunId = Guid.NewGuid();
|
_activeRunId = Guid.NewGuid();
|
||||||
_activeRecipeSnapshot = TestRecipeSnapshot.FromRecipe(Recipe);
|
_activeRecipeSnapshot = TestRecipeSnapshot.FromRecipe(Recipe);
|
||||||
|
_activeRunStartedByPlc = startedByPlc;
|
||||||
_displayedRecipeSnapshot = _activeRecipeSnapshot;
|
_displayedRecipeSnapshot = _activeRecipeSnapshot;
|
||||||
_isShowingHistoricalRun = false;
|
_isShowingHistoricalRun = false;
|
||||||
_currentRunSamples.Clear();
|
_currentRunSamples.Clear();
|
||||||
@@ -711,12 +739,14 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
}
|
}
|
||||||
else if (isRecoveringActiveRun)
|
else if (isRecoveringActiveRun)
|
||||||
{
|
{
|
||||||
|
_activeRunStartedByPlc |= startedByPlc;
|
||||||
_isShowingHistoricalRun = false;
|
_isShowingHistoricalRun = false;
|
||||||
_displayedRecipeSnapshot = _activeRecipeSnapshot;
|
_displayedRecipeSnapshot = _activeRecipeSnapshot;
|
||||||
AddInfoEvent($"试验通信恢复后继续运行,已保留 {_currentRunSamples.Count} 个采样点。");
|
AddInfoEvent($"试验通信恢复后继续运行,已保留 {_currentRunSamples.Count} 个采样点。");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
_activeRunStartedByPlc |= startedByPlc;
|
||||||
AddInfoEvent("试验继续运行。");
|
AddInfoEvent("试验继续运行。");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -728,8 +758,16 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
RaiseStatusProperties();
|
RaiseStatusProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Pause()
|
private async void Pause()
|
||||||
{
|
{
|
||||||
|
if (_activeRunStartedByPlc)
|
||||||
|
{
|
||||||
|
if (!await ExecutePlcPulseCommandAsync("暂停", CoilStop, updateLocalState: false))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_timer.Stop();
|
_timer.Stop();
|
||||||
_machineRuntimeState = MachineRuntimeState.Paused;
|
_machineRuntimeState = MachineRuntimeState.Paused;
|
||||||
MachineState = "暂停";
|
MachineState = "暂停";
|
||||||
@@ -783,7 +821,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
|
|
||||||
if (await ExecutePlcPulseCommandAsync("启动", CoilStart, updateLocalState: false))
|
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);
|
_lastCompletedRecipeSnapshot = _activeRecipeSnapshot ?? TestRecipeSnapshot.FromRecipe(Recipe);
|
||||||
_lastCompletedSamples = _currentRunSamples.ToArray();
|
_lastCompletedSamples = _currentRunSamples.ToArray();
|
||||||
PersistLastCompletedRun();
|
PersistLastCompletedRun();
|
||||||
|
ResetActiveRunContext();
|
||||||
SelectedRunRecord = record;
|
SelectedRunRecord = record;
|
||||||
NextRunIndex++;
|
NextRunIndex++;
|
||||||
UpdateDerivedValues();
|
UpdateDerivedValues();
|
||||||
@@ -1280,6 +1319,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
{
|
{
|
||||||
_activeRunId = Guid.Empty;
|
_activeRunId = Guid.Empty;
|
||||||
_activeRecipeSnapshot = null;
|
_activeRecipeSnapshot = null;
|
||||||
|
_activeRunStartedByPlc = false;
|
||||||
_currentRunSamples.Clear();
|
_currentRunSamples.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1357,12 +1397,19 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var master = _deviceConnectionService.Master;
|
var master = _deviceConnectionService.Master;
|
||||||
Recipe.SledMassGrams = await ReadFloatHoldingRegisterAsync(master, RegisterSledMassGrams);
|
var sledMassGrams = await ReadFloatHoldingRegisterAsync(master, RegisterSledMassGrams);
|
||||||
Recipe.LiftSpeedMmPerMin = await ReadFloatHoldingRegisterAsync(master, RegisterLiftSpeed);
|
var liftSpeedMmPerMin = await ReadFloatHoldingRegisterAsync(master, RegisterLiftSpeed);
|
||||||
Recipe.LiftDisplacementMm = await ReadFloatHoldingRegisterAsync(master, RegisterLiftDisplacement);
|
var liftDisplacementMm = await ReadFloatHoldingRegisterAsync(master, RegisterLiftDisplacement);
|
||||||
Recipe.SpeedMmPerMin = await ReadFloatHoldingRegisterAsync(master, RegisterHorizontalSpeed);
|
var speedMmPerMin = await ReadFloatHoldingRegisterAsync(master, RegisterHorizontalSpeed);
|
||||||
Recipe.TravelMm = await ReadFloatHoldingRegisterAsync(master, RegisterHorizontalDisplacement);
|
var travelMm = await ReadFloatHoldingRegisterAsync(master, RegisterHorizontalDisplacement);
|
||||||
Recipe.ReplicateCount = Math.Clamp((int)Math.Round(await ReadFloatHoldingRegisterAsync(master, RegisterReplicateCount)), 0, 1);
|
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
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user