添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
794
MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/MainViewModel.cs
Normal file
794
MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/MainViewModel.cs
Normal file
@@ -0,0 +1,794 @@
|
||||
using MainShell.Common;
|
||||
using MainShell.Common.Display.ViewModel;
|
||||
using MainShell.EventArgsFolder;
|
||||
using MainShell.Models;
|
||||
using MainShell.Process;
|
||||
using MainShell.ProcessResult;
|
||||
using MainShell.Recipe.Models;
|
||||
using MainShell.Resources.CustomControl;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.AlarmManager;
|
||||
using MW.WorkFlow;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MainShell
|
||||
{
|
||||
public class MainViewModel : BaseScreen, IPage, IHandle<ProcessFlowStateChangedEventArgs>
|
||||
{
|
||||
public string Name { get; set; } = "Home";
|
||||
|
||||
private readonly IAlarmManager _alarmManager;
|
||||
private readonly RecipeManager _recipeManager;
|
||||
private readonly ProcessResultManager _processResultManager;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly FlowStageMappingConfig _flowStageMappingConfig;
|
||||
private readonly WaferHandlingFlowConfig _waferHandlingFlowConfig;
|
||||
private readonly WorkflowRunner _runner;
|
||||
private readonly AutoProductionWorkflowBuilder _autoProductionWorkflowBuilder;
|
||||
private readonly PreparationAreaService _preparationAreaService;
|
||||
private bool _suspendDashboardPersist;
|
||||
private CancellationTokenSource _simulateCts;
|
||||
private bool _simulateFaultRequested;
|
||||
private string _currentSimulatingFlowName;
|
||||
private bool _isProcessPaused;
|
||||
|
||||
public WorkflowRunner Runner => _runner;
|
||||
|
||||
public bool IsProcessPaused
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isProcessPaused;
|
||||
}
|
||||
private set
|
||||
{
|
||||
SetAndNotify(ref _isProcessPaused, value);
|
||||
NotifyOfPropertyChange(nameof(CanPauseProcess));
|
||||
NotifyOfPropertyChange(nameof(CanResumeProcess));
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanPauseProcess
|
||||
{
|
||||
get
|
||||
{
|
||||
return Runner.IsRunning && !IsProcessPaused;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanResumeProcess
|
||||
{
|
||||
get
|
||||
{
|
||||
return Runner.IsRunning && IsProcessPaused;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Brush GrayBrush = new SolidColorBrush(Color.FromRgb(128, 128, 128));
|
||||
private static readonly Brush RunningBrush = new SolidColorBrush(Color.FromRgb(34, 197, 94));
|
||||
private static readonly Brush PausedBrush = new SolidColorBrush(Color.FromRgb(245, 158, 11));
|
||||
private static readonly Brush FaultedBrush = new SolidColorBrush(Color.FromRgb(239, 68, 68));
|
||||
private static readonly Brush CompletedBrush = new SolidColorBrush(Color.FromRgb(59, 130, 246));
|
||||
|
||||
public CameraViewModel CameraSearchViewModel { get; }
|
||||
public CameraViewModel CameraLocateViewModel { get; }
|
||||
public CameraViewModel CameraInspectViewModel { get; }
|
||||
|
||||
public DieMapModel SubstrateMapModel { get; } = new DieMapModel();
|
||||
public DieMapModel WaferMapModel { get; } = new DieMapModel();
|
||||
|
||||
public ProductionDashboardState DashboardState => _processResultManager.DashboardState;
|
||||
|
||||
public ObservableCollection<FlowNodeItem> FlowNodes { get; } = new ObservableCollection<FlowNodeItem>();
|
||||
private readonly Dictionary<string, FlowNodeItem> _flowNodeMap = new Dictionary<string, FlowNodeItem>(StringComparer.OrdinalIgnoreCase);
|
||||
public ObservableCollection<FlowNodeItem> WaferFlowNodes { get; } = new ObservableCollection<FlowNodeItem>();
|
||||
private readonly Dictionary<string, FlowNodeItem> _waferFlowNodeMap = new Dictionary<string, FlowNodeItem>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private string _selectedFlowName;
|
||||
public string SelectedFlowName
|
||||
{
|
||||
get => _selectedFlowName;
|
||||
set => SetAndNotify(ref _selectedFlowName, value);
|
||||
}
|
||||
|
||||
private string _currentFlowName = "未运行";
|
||||
public string CurrentFlowName
|
||||
{
|
||||
get => _currentFlowName;
|
||||
set => SetAndNotify(ref _currentFlowName, value);
|
||||
}
|
||||
|
||||
private Brush _loadStageBrush = GrayBrush;
|
||||
public Brush LoadStageBrush
|
||||
{
|
||||
get => _loadStageBrush;
|
||||
set => SetAndNotify(ref _loadStageBrush, value);
|
||||
}
|
||||
|
||||
private Brush _alignStageBrush = GrayBrush;
|
||||
public Brush AlignStageBrush
|
||||
{
|
||||
get => _alignStageBrush;
|
||||
set => SetAndNotify(ref _alignStageBrush, value);
|
||||
}
|
||||
|
||||
private Brush _bondStageBrush = GrayBrush;
|
||||
public Brush BondStageBrush
|
||||
{
|
||||
get => _bondStageBrush;
|
||||
set => SetAndNotify(ref _bondStageBrush, value);
|
||||
}
|
||||
|
||||
private Brush _inspectStageBrush = GrayBrush;
|
||||
public Brush InspectStageBrush
|
||||
{
|
||||
get => _inspectStageBrush;
|
||||
set => SetAndNotify(ref _inspectStageBrush, value);
|
||||
}
|
||||
|
||||
private Brush _unloadStageBrush = GrayBrush;
|
||||
public Brush UnloadStageBrush
|
||||
{
|
||||
get => _unloadStageBrush;
|
||||
set => SetAndNotify(ref _unloadStageBrush, value);
|
||||
}
|
||||
|
||||
private string _substrateRecipe = "-";
|
||||
public string SubstrateRecipe
|
||||
{
|
||||
get => _substrateRecipe;
|
||||
set => SetAndNotify(ref _substrateRecipe, value);
|
||||
}
|
||||
|
||||
private string _chipRecipe = "-";
|
||||
public string ChipRecipe
|
||||
{
|
||||
get => _chipRecipe;
|
||||
set => SetAndNotify(ref _chipRecipe, value);
|
||||
}
|
||||
|
||||
private int _rejectCount = 12;
|
||||
public int RejectCount
|
||||
{
|
||||
get => _rejectCount;
|
||||
set => SetAndNotify(ref _rejectCount, value);
|
||||
}
|
||||
|
||||
public MainViewModel(
|
||||
IAlarmManager alarmManager,
|
||||
RecipeManager recipeManager,
|
||||
ProcessResultManager processResultManager,
|
||||
IEventAggregator eventAggregator,
|
||||
WorkflowRunner runner,
|
||||
AutoProductionWorkflowBuilder autoProductionWorkflowBuilder,
|
||||
PreparationAreaService preparationAreaService)
|
||||
{
|
||||
_alarmManager = alarmManager;
|
||||
_recipeManager = recipeManager;
|
||||
_processResultManager = processResultManager;
|
||||
_eventAggregator = eventAggregator;
|
||||
_runner = runner;
|
||||
_autoProductionWorkflowBuilder = autoProductionWorkflowBuilder;
|
||||
_preparationAreaService = preparationAreaService ?? throw new ArgumentNullException(nameof(preparationAreaService));
|
||||
_flowStageMappingConfig = FlowStageMappingConfig.LoadOrCreate();
|
||||
_waferHandlingFlowConfig = WaferHandlingFlowConfig.LoadOrCreate();
|
||||
|
||||
CameraSearchViewModel = new CameraViewModel(_eventAggregator, CameraType.TopPositionCamera);
|
||||
CameraLocateViewModel = new CameraViewModel(_eventAggregator, CameraType.MapCamera);
|
||||
CameraInspectViewModel = new CameraViewModel(_eventAggregator, CameraType.TopWideCamera);
|
||||
|
||||
_eventAggregator.Subscribe(this);
|
||||
_recipeManager.RecipesChanged += OnRecipesChanged;
|
||||
DashboardState.PropertyChanged += OnDashboardStatePropertyChanged;
|
||||
_runner.PropertyChanged += OnRunnerPropertyChanged;
|
||||
|
||||
InitializeFlowNodes();
|
||||
InitializeWaferFlowNodes();
|
||||
InitMapData();
|
||||
RefreshRecipeBindings();
|
||||
RefreshFlowBindings();
|
||||
RestoreDashboardState();
|
||||
}
|
||||
|
||||
private void OnRunnerPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (!string.Equals(e.PropertyName, nameof(WorkflowRunner.IsRunning), StringComparison.Ordinal))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Runner.IsRunning)
|
||||
{
|
||||
IsProcessPaused = false;
|
||||
}
|
||||
|
||||
NotifyOfPropertyChange(nameof(CanPauseProcess));
|
||||
NotifyOfPropertyChange(nameof(CanResumeProcess));
|
||||
}
|
||||
|
||||
private void OnDashboardStatePropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
PersistDashboardState();
|
||||
}
|
||||
|
||||
private void RestoreDashboardState()
|
||||
{
|
||||
var s = _processResultManager.DashboardState;
|
||||
_suspendDashboardPersist = true;
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(s.ProductId)) DashboardState.ProductId = s.ProductId;
|
||||
if (!string.IsNullOrWhiteSpace(s.ChipId)) DashboardState.ChipId = s.ChipId;
|
||||
|
||||
DashboardState.ProcessedSubstrateTotal = s.ProcessedSubstrateTotal;
|
||||
DashboardState.PendingCount = s.PendingCount;
|
||||
DashboardState.ProcessedCount = s.ProcessedCount;
|
||||
DashboardState.RealTimeUph = s.RealTimeUph;
|
||||
DashboardState.YieldUph = s.YieldUph;
|
||||
DashboardState.MappingProgress = s.MappingProgress;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_suspendDashboardPersist = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void PersistDashboardState()
|
||||
{
|
||||
if (_suspendDashboardPersist) return;
|
||||
|
||||
var s = _processResultManager.DashboardState;
|
||||
s.ProductId = DashboardState.ProductId;
|
||||
s.ChipId = DashboardState.ChipId;
|
||||
s.ProcessedSubstrateTotal = DashboardState.ProcessedSubstrateTotal;
|
||||
s.PendingCount = DashboardState.PendingCount;
|
||||
s.ProcessedCount = DashboardState.ProcessedCount;
|
||||
s.RealTimeUph = DashboardState.RealTimeUph;
|
||||
s.YieldUph = DashboardState.YieldUph;
|
||||
s.MappingProgress = DashboardState.MappingProgress;
|
||||
|
||||
_processResultManager.SaveDashboardState();
|
||||
}
|
||||
|
||||
private void InitializeFlowNodes()
|
||||
{
|
||||
FlowNodes.Clear();
|
||||
_flowNodeMap.Clear();
|
||||
|
||||
var flowDisplayNameMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ ProcessFlowName.SubstrateLoadFlow, "基板上料" },
|
||||
{ ProcessFlowName.SubstratePositionFlow, "基板定位" },
|
||||
{ ProcessFlowName.ChipStraighteningFlow, "芯片拉直" },
|
||||
{ ProcessFlowName.DiePositionFlow, "芯片定位" },
|
||||
{ ProcessFlowName.DieTransferFlow, "芯片转移" },
|
||||
{ ProcessFlowName.DieRecheckFlow, "精度复检" },
|
||||
{ ProcessFlowName.SubstrateUnloadFlow, "基板下料" }
|
||||
};
|
||||
|
||||
var flows = _flowStageMappingConfig.Rules
|
||||
.Where(r => !string.IsNullOrWhiteSpace(r.WorkflowName))
|
||||
.Where(r => !string.Equals(r.WorkflowName, ProcessFlowName.AutoProduction, StringComparison.OrdinalIgnoreCase))
|
||||
.GroupBy(r => r.WorkflowName, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(g => g.First())
|
||||
.OrderBy(r => r.Stage)
|
||||
.ThenBy(r => r.WorkflowName)
|
||||
.ToList();
|
||||
|
||||
foreach (var f in flows)
|
||||
{
|
||||
var name = flowDisplayNameMap.ContainsKey(f.WorkflowName) ? flowDisplayNameMap[f.WorkflowName] : f.WorkflowName;
|
||||
var node = new FlowNodeItem
|
||||
{
|
||||
FlowName = f.WorkflowName,
|
||||
DisplayName = name,
|
||||
Brush = GrayBrush
|
||||
};
|
||||
FlowNodes.Add(node);
|
||||
_flowNodeMap[f.WorkflowName] = node;
|
||||
}
|
||||
|
||||
if (FlowNodes.Count > 0)
|
||||
{
|
||||
SelectedFlowName = FlowNodes[0].FlowName;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeWaferFlowNodes()
|
||||
{
|
||||
WaferFlowNodes.Clear();
|
||||
_waferFlowNodeMap.Clear();
|
||||
|
||||
var nodes = _waferHandlingFlowConfig.Nodes;
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
AddWaferFlowNode(node.Key, node.DisplayName);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddWaferFlowNode(string key, string displayName)
|
||||
{
|
||||
var node = new FlowNodeItem
|
||||
{
|
||||
FlowName = key,
|
||||
DisplayName = displayName,
|
||||
Brush = GrayBrush
|
||||
};
|
||||
|
||||
WaferFlowNodes.Add(node);
|
||||
_waferFlowNodeMap[key] = node;
|
||||
}
|
||||
|
||||
private void OnRecipesChanged(object sender, EventArgs e)
|
||||
{
|
||||
Execute.OnUIThread(RefreshRecipeBindings);
|
||||
}
|
||||
|
||||
private void RefreshRecipeBindings()
|
||||
{
|
||||
SubstrateRecipe = _recipeManager.CurrentSubstrateRecipe != null
|
||||
? _recipeManager.CurrentSubstrateRecipe.RecipeName
|
||||
: "-";
|
||||
|
||||
ChipRecipe = _recipeManager.CurrentWaferRecipe != null
|
||||
? _recipeManager.CurrentWaferRecipe.RecipeName
|
||||
: "-";
|
||||
}
|
||||
|
||||
private void RefreshFlowBindings()
|
||||
{
|
||||
var flow = _processResultManager.FlowState;
|
||||
var displayFlow = _flowStageMappingConfig.ResolveDisplayFlowName(flow.WorkflowName, flow.ParentActivityName, flow.CurrentActivityName);
|
||||
CurrentFlowName = string.IsNullOrWhiteSpace(displayFlow) ? "未运行" : displayFlow;
|
||||
ProcessExecutionStatus status;
|
||||
if (!Enum.TryParse(flow.Status, true, out status))
|
||||
{
|
||||
status = ProcessExecutionStatus.Unknown;
|
||||
}
|
||||
|
||||
UpdateFlowVisual(status, flow.WorkflowName, flow.ParentActivityName, flow.CurrentActivityName);
|
||||
}
|
||||
|
||||
private void UpdateFlowVisual(ProcessExecutionStatus status, string workflowName, string parentFlowName, string activityName)
|
||||
{
|
||||
LoadStageBrush = GrayBrush;
|
||||
AlignStageBrush = GrayBrush;
|
||||
BondStageBrush = GrayBrush;
|
||||
InspectStageBrush = GrayBrush;
|
||||
UnloadStageBrush = GrayBrush;
|
||||
|
||||
var stage = _flowStageMappingConfig.Resolve(workflowName, parentFlowName, activityName);
|
||||
var stageIndex = (int)stage;
|
||||
|
||||
if (stageIndex > 0) LoadStageBrush = CompletedBrush;
|
||||
if (stageIndex > 1) AlignStageBrush = CompletedBrush;
|
||||
if (stageIndex > 2) BondStageBrush = CompletedBrush;
|
||||
if (stageIndex > 3) InspectStageBrush = CompletedBrush;
|
||||
|
||||
Brush currentBrush = GrayBrush;
|
||||
switch (status)
|
||||
{
|
||||
case ProcessExecutionStatus.Running:
|
||||
currentBrush = RunningBrush;
|
||||
break;
|
||||
case ProcessExecutionStatus.Paused:
|
||||
case ProcessExecutionStatus.Canceled:
|
||||
currentBrush = PausedBrush;
|
||||
break;
|
||||
case ProcessExecutionStatus.Faulted:
|
||||
currentBrush = FaultedBrush;
|
||||
break;
|
||||
case ProcessExecutionStatus.Completed:
|
||||
currentBrush = CompletedBrush;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (stageIndex)
|
||||
{
|
||||
case 0: LoadStageBrush = currentBrush; break;
|
||||
case 1: AlignStageBrush = currentBrush; break;
|
||||
case 2: BondStageBrush = currentBrush; break;
|
||||
case 3: InspectStageBrush = currentBrush; break;
|
||||
case 4: UnloadStageBrush = currentBrush; break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(ProcessFlowStateChangedEventArgs message)
|
||||
{
|
||||
Execute.OnUIThread(() =>
|
||||
{
|
||||
var displayFlow = _flowStageMappingConfig.ResolveDisplayFlowName(message.WorkflowName, message.ParentActivityName, message.CurrentActivityName);
|
||||
CurrentFlowName = string.IsNullOrWhiteSpace(displayFlow) ? "未运行" : displayFlow;
|
||||
UpdateFlowVisual(message.Status, message.WorkflowName, message.ParentActivityName, message.CurrentActivityName);
|
||||
UpdateFlowNodes(message);
|
||||
UpdateWaferFlowNodes(message);
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateFlowNodes(ProcessFlowStateChangedEventArgs message)
|
||||
{
|
||||
foreach (var node in FlowNodes)
|
||||
{
|
||||
node.Brush = GrayBrush;
|
||||
}
|
||||
|
||||
var activeFlow = ResolveActiveMainFlowKey(message);
|
||||
if (string.IsNullOrWhiteSpace(activeFlow) || !_flowNodeMap.ContainsKey(activeFlow)) return;
|
||||
|
||||
_flowNodeMap[activeFlow].Brush = ResolveStatusBrush(message.Status);
|
||||
}
|
||||
|
||||
private string ResolveActiveMainFlowKey(ProcessFlowStateChangedEventArgs message)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(message.WorkflowName) && _flowNodeMap.ContainsKey(message.WorkflowName))
|
||||
{
|
||||
return message.WorkflowName;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(message.ParentActivityName) && _flowNodeMap.ContainsKey(message.ParentActivityName))
|
||||
{
|
||||
return message.ParentActivityName;
|
||||
}
|
||||
|
||||
var displayFlow = _flowStageMappingConfig.ResolveDisplayFlowName(message.WorkflowName, message.ParentActivityName, message.CurrentActivityName);
|
||||
if (!string.IsNullOrWhiteSpace(displayFlow) && _flowNodeMap.ContainsKey(displayFlow))
|
||||
{
|
||||
return displayFlow;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void UpdateWaferFlowNodes(ProcessFlowStateChangedEventArgs message)
|
||||
{
|
||||
foreach (var node in WaferFlowNodes)
|
||||
{
|
||||
node.Brush = GrayBrush;
|
||||
}
|
||||
|
||||
var activeFlow = ResolveActiveWaferFlowKey(message);
|
||||
if (string.IsNullOrWhiteSpace(activeFlow) || !_waferFlowNodeMap.ContainsKey(activeFlow)) return;
|
||||
|
||||
_waferFlowNodeMap[activeFlow].Brush = ResolveStatusBrush(message.Status);
|
||||
}
|
||||
|
||||
private string ResolveActiveWaferFlowKey(ProcessFlowStateChangedEventArgs message)
|
||||
{
|
||||
return _waferHandlingFlowConfig.ResolveNodeKey(
|
||||
message.WorkflowName,
|
||||
message.ParentActivityName,
|
||||
message.CurrentActivityName);
|
||||
}
|
||||
|
||||
private static Brush ResolveStatusBrush(ProcessExecutionStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case ProcessExecutionStatus.Running:
|
||||
return RunningBrush;
|
||||
case ProcessExecutionStatus.Paused:
|
||||
case ProcessExecutionStatus.Canceled:
|
||||
return PausedBrush;
|
||||
case ProcessExecutionStatus.Faulted:
|
||||
return FaultedBrush;
|
||||
case ProcessExecutionStatus.Completed:
|
||||
return CompletedBrush;
|
||||
default:
|
||||
return GrayBrush;
|
||||
}
|
||||
}
|
||||
|
||||
public async System.Threading.Tasks.Task StartProcess()
|
||||
{
|
||||
if (Runner.IsRunning) return;
|
||||
|
||||
if (_simulateCts != null) return;
|
||||
|
||||
IsProcessPaused = false;
|
||||
|
||||
WorkflowStartRequest workflowStartRequest = _autoProductionWorkflowBuilder.Create(SelectedFlowName);
|
||||
|
||||
try
|
||||
{
|
||||
WorkflowRunCompletedEventArgs completedArgs = await Runner.RunWithResultAsync(
|
||||
workflowStartRequest.Definition,
|
||||
workflowStartRequest.Context,
|
||||
workflowStartRequest.StartStepId);
|
||||
|
||||
if (completedArgs.FinalState == WorkflowState.Faulted)
|
||||
{
|
||||
ShowWorkflowFailureDialog(completedArgs);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LocalizedMessageBox.ShowFormat(
|
||||
MessageKey.ProcessFailedWithReason,
|
||||
MessageKey.TitleError,
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error,
|
||||
ex.Message ?? LanguageResourceHelper.GetString(MessageKey.CommonUnknownError));
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsProcessPaused = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void PauseProcess()
|
||||
{
|
||||
if (!Runner.IsRunning || IsProcessPaused || _simulateCts != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Runner.Pause();
|
||||
_preparationAreaService.Pause();
|
||||
UpdateCurrentProcessStatus(ProcessExecutionStatus.Paused);
|
||||
IsProcessPaused = true;
|
||||
}
|
||||
|
||||
public void ResumeProcess()
|
||||
{
|
||||
if (!Runner.IsRunning || !IsProcessPaused || _simulateCts != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_preparationAreaService.Resume();
|
||||
Runner.Resume();
|
||||
UpdateCurrentProcessStatus(ProcessExecutionStatus.Running);
|
||||
IsProcessPaused = false;
|
||||
}
|
||||
|
||||
private void ShowWorkflowFailureDialog(WorkflowRunCompletedEventArgs completedArgs)
|
||||
{
|
||||
if (completedArgs == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
object[] failureMessageArguments = completedArgs.FailureMessageArguments ?? Array.Empty<object>();
|
||||
if (completedArgs.FailureMessageKey != MessageKey.None)
|
||||
{
|
||||
if (failureMessageArguments.Length > 0)
|
||||
{
|
||||
LocalizedMessageBox.ShowFormat(
|
||||
completedArgs.FailureMessageKey,
|
||||
MessageKey.TitleError,
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error,
|
||||
failureMessageArguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
LocalizedMessageBox.Show(
|
||||
completedArgs.FailureMessageKey,
|
||||
MessageKey.TitleError,
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
string failureMessage = string.IsNullOrWhiteSpace(completedArgs.FailureMessage)
|
||||
? LanguageResourceHelper.GetString(MessageKey.CommonUnknownError)
|
||||
: completedArgs.FailureMessage;
|
||||
|
||||
LocalizedMessageBox.ShowFormat(
|
||||
MessageKey.ProcessFailedWithReason,
|
||||
MessageKey.TitleError,
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error,
|
||||
failureMessage);
|
||||
}
|
||||
|
||||
public async System.Threading.Tasks.Task StopProcess()
|
||||
{
|
||||
if (_simulateCts != null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_currentSimulatingFlowName))
|
||||
{
|
||||
_eventAggregator.Publish(new ProcessFlowStateChangedEventArgs
|
||||
{
|
||||
WorkflowName = _currentSimulatingFlowName,
|
||||
ParentActivityName = _currentSimulatingFlowName,
|
||||
CurrentActivityName = _currentSimulatingFlowName,
|
||||
Status = ProcessExecutionStatus.Canceled
|
||||
});
|
||||
}
|
||||
_simulateCts.Cancel();
|
||||
}
|
||||
|
||||
await _preparationAreaService.CancelAsync(CancellationToken.None);
|
||||
await Runner.StopAsync();
|
||||
IsProcessPaused = false;
|
||||
}
|
||||
|
||||
private void UpdateCurrentProcessStatus(ProcessExecutionStatus status)
|
||||
{
|
||||
ProcessFlowState flowState = _processResultManager.FlowState;
|
||||
string workflowName = string.IsNullOrWhiteSpace(flowState.WorkflowName)
|
||||
? ProcessFlowName.AutoProduction
|
||||
: flowState.WorkflowName;
|
||||
|
||||
_processResultManager.UpdateFlowState(
|
||||
workflowName,
|
||||
flowState.ParentActivityName,
|
||||
flowState.CurrentActivityName,
|
||||
status,
|
||||
flowState.ErrorMessage);
|
||||
}
|
||||
|
||||
public void TriggerSimulateFault()
|
||||
{
|
||||
_simulateFaultRequested = true;
|
||||
}
|
||||
|
||||
private async Task SimulateFlowRuntimeAsync()
|
||||
{
|
||||
_simulateCts = new CancellationTokenSource();
|
||||
try
|
||||
{
|
||||
var token = _simulateCts.Token;
|
||||
foreach (var node in FlowNodes)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
_currentSimulatingFlowName = node.FlowName;
|
||||
|
||||
_eventAggregator.Publish(new ProcessFlowStateChangedEventArgs
|
||||
{
|
||||
WorkflowName = node.FlowName,
|
||||
ParentActivityName = node.FlowName,
|
||||
CurrentActivityName = node.FlowName,
|
||||
Status = ProcessExecutionStatus.Running
|
||||
});
|
||||
|
||||
await Task.Delay(700, token);
|
||||
|
||||
if (_simulateFaultRequested)
|
||||
{
|
||||
_eventAggregator.Publish(new ProcessFlowStateChangedEventArgs
|
||||
{
|
||||
WorkflowName = node.FlowName,
|
||||
ParentActivityName = node.FlowName,
|
||||
CurrentActivityName = node.FlowName,
|
||||
Status = ProcessExecutionStatus.Faulted,
|
||||
ErrorMessage = "模拟流程异常"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
_eventAggregator.Publish(new ProcessFlowStateChangedEventArgs
|
||||
{
|
||||
WorkflowName = node.FlowName,
|
||||
ParentActivityName = node.FlowName,
|
||||
CurrentActivityName = node.FlowName,
|
||||
Status = ProcessExecutionStatus.Completed
|
||||
});
|
||||
|
||||
await Task.Delay(250, token);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_currentSimulatingFlowName))
|
||||
{
|
||||
_eventAggregator.Publish(new ProcessFlowStateChangedEventArgs
|
||||
{
|
||||
WorkflowName = _currentSimulatingFlowName,
|
||||
ParentActivityName = _currentSimulatingFlowName,
|
||||
CurrentActivityName = _currentSimulatingFlowName,
|
||||
Status = ProcessExecutionStatus.Canceled
|
||||
});
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_currentSimulatingFlowName = null;
|
||||
_simulateFaultRequested = false;
|
||||
_simulateCts.Dispose();
|
||||
_simulateCts = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetFlowVisuals()
|
||||
{
|
||||
foreach (var node in FlowNodes)
|
||||
{
|
||||
node.Brush = GrayBrush;
|
||||
}
|
||||
|
||||
foreach (var node in WaferFlowNodes)
|
||||
{
|
||||
node.Brush = GrayBrush;
|
||||
}
|
||||
|
||||
LoadStageBrush = GrayBrush;
|
||||
AlignStageBrush = GrayBrush;
|
||||
BondStageBrush = GrayBrush;
|
||||
InspectStageBrush = GrayBrush;
|
||||
UnloadStageBrush = GrayBrush;
|
||||
CurrentFlowName = "未运行";
|
||||
}
|
||||
|
||||
public void ClearStatistics()
|
||||
{
|
||||
_suspendDashboardPersist = true;
|
||||
DashboardState.ProcessedSubstrateTotal = 0;
|
||||
DashboardState.RealTimeUph = 0;
|
||||
DashboardState.YieldUph = 0;
|
||||
DashboardState.MappingProgress = 0;
|
||||
DashboardState.ProcessedCount = 0;
|
||||
_suspendDashboardPersist = false;
|
||||
PersistDashboardState();
|
||||
}
|
||||
|
||||
private void InitMapData()
|
||||
{
|
||||
SubstrateMapModel.Initialize(36, 36);
|
||||
WaferMapModel.Initialize(36, 36);
|
||||
|
||||
var rand = new Random();
|
||||
for (int r = 0; r < 36; r++)
|
||||
{
|
||||
for (int c = 0; c < 36; c++)
|
||||
{
|
||||
var dist = Math.Sqrt(Math.Pow(r - 18, 2) + Math.Pow(c - 18, 2));
|
||||
if (dist > 17)
|
||||
{
|
||||
WaferMapModel.SetDieState(r, c, DieState.NotExist);
|
||||
}
|
||||
else
|
||||
{
|
||||
var v = rand.Next(100);
|
||||
if (v < 3)
|
||||
WaferMapModel.SetDieState(r, c, DieState.Error);
|
||||
else if (v < 40)
|
||||
WaferMapModel.SetDieState(r, c, DieState.Used);
|
||||
else
|
||||
WaferMapModel.SetDieState(r, c, DieState.Available);
|
||||
}
|
||||
|
||||
var sv = rand.Next(100);
|
||||
if (sv < 2)
|
||||
SubstrateMapModel.SetDieState(r, c, DieState.Error);
|
||||
else if (sv < 45)
|
||||
SubstrateMapModel.SetDieState(r, c, DieState.Used);
|
||||
else
|
||||
SubstrateMapModel.SetDieState(r, c, DieState.Available);
|
||||
}
|
||||
}
|
||||
|
||||
SubstrateMapModel.SetDieState(16, 20, DieState.Target);
|
||||
WaferMapModel.SetDieState(14, 14, DieState.Current);
|
||||
}
|
||||
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
base.OnViewLoaded();
|
||||
}
|
||||
|
||||
public class FlowNodeItem : PropertyChangedBase
|
||||
{
|
||||
private Brush _brush;
|
||||
public string FlowName { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public Brush Brush
|
||||
{
|
||||
get => _brush;
|
||||
set => SetAndNotify(ref _brush, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user