299 lines
11 KiB
C#
299 lines
11 KiB
C#
|
|
using MainShell.Common;
|
|||
|
|
using MainShell.EventArgsFolder;
|
|||
|
|
using MainShell.Process;
|
|||
|
|
using Stylet;
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Linq;
|
|||
|
|
using System.Text;
|
|||
|
|
using System.Threading.Tasks;
|
|||
|
|
using MW.WorkFlow;
|
|||
|
|
|
|||
|
|
namespace MainShell.ProcessResult
|
|||
|
|
{
|
|||
|
|
public class ProcessResultManager
|
|||
|
|
{
|
|||
|
|
private readonly MachineState _machineState;
|
|||
|
|
private readonly IEventAggregator _eventAggregator;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 流程运行状态记录(仅在自动模式下持久化)
|
|||
|
|
/// </summary>
|
|||
|
|
public ProcessFlowState FlowState { get; } = new ProcessFlowState();
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 基板定位的业务结果数据(始终持久化)
|
|||
|
|
/// </summary>
|
|||
|
|
public SubstratePositionProcessResult SubstratePositionResult { get; } = new SubstratePositionProcessResult();
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 芯片定位的业务结果数据(始终持久化)
|
|||
|
|
/// </summary>
|
|||
|
|
public DiePositionProcessResult DiePositionResult { get; } = new DiePositionProcessResult();
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 基板测高的业务结果数据(始终持久化)
|
|||
|
|
/// </summary>
|
|||
|
|
public SubstrateHeightMeasureProcessResult SubstrateHeightMeasureResult { get; } = new SubstrateHeightMeasureProcessResult();
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 精度复检的业务结果数据(始终持久化)
|
|||
|
|
/// </summary>
|
|||
|
|
public DieRecheckProcessResult DieRecheckResult { get; } = new DieRecheckProcessResult();
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 首页统计与条码展示状态(始终持久化)
|
|||
|
|
/// </summary>
|
|||
|
|
public ProductionDashboardState DashboardState { get; } = new ProductionDashboardState();
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 准备区状态(用于恢复前一致性校验)
|
|||
|
|
/// </summary>
|
|||
|
|
public PreparationAreaProcessState PreparationAreaState { get; } = new PreparationAreaProcessState();
|
|||
|
|
|
|||
|
|
private readonly AutoProductionResumeValidator _resumeValidator = new AutoProductionResumeValidator();
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 当前芯片使用位状态
|
|||
|
|
/// </summary>
|
|||
|
|
public CurrentChipProcessState CurrentChipState { get; } = new CurrentChipProcessState();
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 自动流程运行态
|
|||
|
|
/// </summary>
|
|||
|
|
public AutoProductionRuntimeState AutoProductionRuntimeState { get; } = new AutoProductionRuntimeState();
|
|||
|
|
|
|||
|
|
public ProcessResultManager(MachineState machineState, IEventAggregator eventAggregator)
|
|||
|
|
{
|
|||
|
|
_machineState = machineState ?? throw new ArgumentNullException(nameof(machineState));
|
|||
|
|
_eventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator));
|
|||
|
|
// 构造时读取一次
|
|||
|
|
ReloadAll();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void UpdateFlowState(string workflowName, string parentActivityName, string activityName, ProcessExecutionStatus status, string errorMessage = null)
|
|||
|
|
{
|
|||
|
|
FlowState.WorkflowName = workflowName;
|
|||
|
|
FlowState.ParentActivityName = parentActivityName;
|
|||
|
|
FlowState.CurrentActivityName = activityName;
|
|||
|
|
FlowState.Status = status.ToString();
|
|||
|
|
FlowState.ErrorMessage = errorMessage;
|
|||
|
|
FlowState.LastUpdateTime = DateTime.Now;
|
|||
|
|
|
|||
|
|
if (ShouldPersistFlowState(workflowName))
|
|||
|
|
{
|
|||
|
|
FlowState.Write();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_eventAggregator.Publish(new ProcessFlowStateChangedEventArgs
|
|||
|
|
{
|
|||
|
|
WorkflowName = workflowName,
|
|||
|
|
ParentActivityName = parentActivityName,
|
|||
|
|
CurrentActivityName = activityName,
|
|||
|
|
Status = status,
|
|||
|
|
ErrorMessage = errorMessage
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void UpdateFlowState(string workflowName, string parentActivityName, string activityName, string status, string errorMessage = null)
|
|||
|
|
{
|
|||
|
|
ProcessExecutionStatus parsed;
|
|||
|
|
if (!Enum.TryParse(status, true, out parsed))
|
|||
|
|
{
|
|||
|
|
parsed = ProcessExecutionStatus.Unknown;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UpdateFlowState(workflowName, parentActivityName, activityName, parsed, errorMessage);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void UpdateExecutionPointer(WorkflowExecutionPointer executionPointer)
|
|||
|
|
{
|
|||
|
|
if (executionPointer == null)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
FlowState.WorkflowName = executionPointer.WorkflowName;
|
|||
|
|
FlowState.ParentActivityName = executionPointer.FlowName;
|
|||
|
|
FlowState.CurrentActivityName = executionPointer.ActivityName;
|
|||
|
|
FlowState.CurrentStepId = executionPointer.CurrentStepId;
|
|||
|
|
FlowState.NextStepId = executionPointer.NextStepId;
|
|||
|
|
FlowState.LastUpdateTime = executionPointer.UpdatedAt == default(DateTime) ? DateTime.Now : executionPointer.UpdatedAt;
|
|||
|
|
|
|||
|
|
if (ShouldPersistFlowState(executionPointer.WorkflowName))
|
|||
|
|
{
|
|||
|
|
FlowState.Write();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void ReportWorkflowFault(WorkflowFaultInfo faultInfo)
|
|||
|
|
{
|
|||
|
|
if (faultInfo == null)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
FlowState.WorkflowName = faultInfo.WorkflowName;
|
|||
|
|
FlowState.ParentActivityName = faultInfo.FlowName;
|
|||
|
|
FlowState.CurrentActivityName = faultInfo.ActivityName;
|
|||
|
|
FlowState.CurrentStepId = faultInfo.CurrentStepId;
|
|||
|
|
FlowState.NextStepId = faultInfo.CurrentStepId;
|
|||
|
|
FlowState.Status = ProcessExecutionStatus.Faulted.ToString();
|
|||
|
|
FlowState.ErrorMessage = faultInfo.ErrorMessage;
|
|||
|
|
FlowState.LastUpdateTime = faultInfo.OccurredAt == default(DateTime) ? DateTime.Now : faultInfo.OccurredAt;
|
|||
|
|
|
|||
|
|
if (ShouldPersistFlowState(faultInfo.WorkflowName))
|
|||
|
|
{
|
|||
|
|
FlowState.Write();
|
|||
|
|
}
|
|||
|
|
_eventAggregator.Publish(new ProcessFlowStateChangedEventArgs
|
|||
|
|
{
|
|||
|
|
WorkflowName = faultInfo.WorkflowName,
|
|||
|
|
ParentActivityName = faultInfo.FlowName,
|
|||
|
|
CurrentActivityName = faultInfo.ActivityName,
|
|||
|
|
Status = ProcessExecutionStatus.Faulted,
|
|||
|
|
ErrorMessage = faultInfo.ErrorMessage
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public bool TryGetResumeStepId(string workflowName, out string resumeStepId)
|
|||
|
|
{
|
|||
|
|
resumeStepId = null;
|
|||
|
|
|
|||
|
|
if (string.IsNullOrWhiteSpace(workflowName) ||
|
|||
|
|
!string.Equals(FlowState.WorkflowName, workflowName, StringComparison.OrdinalIgnoreCase) ||
|
|||
|
|
string.IsNullOrWhiteSpace(FlowState.NextStepId))
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (string.Equals(FlowState.Status, ProcessExecutionStatus.Completed.ToString(), StringComparison.OrdinalIgnoreCase) ||
|
|||
|
|
string.Equals(FlowState.Status, ProcessExecutionStatus.Canceled.ToString(), StringComparison.OrdinalIgnoreCase))
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!_resumeValidator.IsStateConsistentForResume(FlowState.NextStepId, PreparationAreaState, CurrentChipState))
|
|||
|
|
{
|
|||
|
|
FlowState.ErrorMessage = _resumeValidator.BuildResumeValidationError(FlowState.NextStepId, PreparationAreaState, CurrentChipState);
|
|||
|
|
FlowState.LastUpdateTime = DateTime.Now;
|
|||
|
|
if (ShouldPersistFlowState(workflowName))
|
|||
|
|
{
|
|||
|
|
FlowState.Write();
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
resumeStepId = FlowState.NextStepId;
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void SaveSubstratePositionResult()
|
|||
|
|
{
|
|||
|
|
SubstratePositionResult.Write();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void SaveDiePositionResult()
|
|||
|
|
{
|
|||
|
|
DiePositionResult.Write();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void SaveSubstrateHeightMeasureResult()
|
|||
|
|
{
|
|||
|
|
SubstrateHeightMeasureResult.Write();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void SaveDieRecheckResult()
|
|||
|
|
{
|
|||
|
|
DieRecheckResult.Write();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void SaveDashboardState()
|
|||
|
|
{
|
|||
|
|
DashboardState.Write();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void SavePreparationAreaState(ChipPreparationStateSnapshot snapshot)
|
|||
|
|
{
|
|||
|
|
if (snapshot == null)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
PreparationAreaState.Status = snapshot.Status;
|
|||
|
|
PreparationAreaState.ActiveRequestId = snapshot.ActiveRequestId;
|
|||
|
|
PreparationAreaState.RecipeName = snapshot.RecipeName;
|
|||
|
|
PreparationAreaState.SourceStepId = snapshot.SourceStepId;
|
|||
|
|
PreparationAreaState.CurrentStage = snapshot.CurrentStage;
|
|||
|
|
PreparationAreaState.ErrorMessage = snapshot.ErrorMessage;
|
|||
|
|
PreparationAreaState.LastUpdatedTime = snapshot.LastUpdatedTime;
|
|||
|
|
PreparationAreaState.CurrentAction = snapshot.CurrentAction;
|
|||
|
|
PreparationAreaState.HasPreparedChip = snapshot.IsChipLoaded;
|
|||
|
|
PreparationAreaState.Write();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void SaveCurrentChipState(CurrentChipLifecycleState chipState)
|
|||
|
|
{
|
|||
|
|
CurrentChipState.State = chipState;
|
|||
|
|
CurrentChipState.LastUpdatedTime = DateTime.Now;
|
|||
|
|
CurrentChipState.Write();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void SaveAutoProductionRuntimeState(AutoProductionRuntimeState runtimeState)
|
|||
|
|
{
|
|||
|
|
if (runtimeState == null)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
AutoProductionRuntimeState.CurrentSubstratePendingCount = runtimeState.CurrentSubstratePendingCount;
|
|||
|
|
AutoProductionRuntimeState.CurrentSubstrateProcessedCount = runtimeState.CurrentSubstrateProcessedCount;
|
|||
|
|
AutoProductionRuntimeState.CurrentChipRemainingCount = runtimeState.CurrentChipRemainingCount;
|
|||
|
|
AutoProductionRuntimeState.TransferNeedsRecheck = runtimeState.TransferNeedsRecheck;
|
|||
|
|
AutoProductionRuntimeState.TransferChipExhausted = runtimeState.TransferChipExhausted;
|
|||
|
|
AutoProductionRuntimeState.LastUpdatedTime = runtimeState.LastUpdatedTime;
|
|||
|
|
AutoProductionRuntimeState.Write();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 强制从磁盘重新加载所有状态和结果数据
|
|||
|
|
/// <para>在启动或恢复自动流程前调用,确保获取到最新的(可能是手动操作产生的)结果数据</para>
|
|||
|
|
/// </summary>
|
|||
|
|
public void ReloadAll()
|
|||
|
|
{
|
|||
|
|
// 1. 读取断点状态(决定从哪一步开始)
|
|||
|
|
FlowState.Read();
|
|||
|
|
|
|||
|
|
// 2. 读取业务结果(决定流程所需的数据上下文)
|
|||
|
|
// 无论之前是手动还是自动写入的,这里统一读取最新值
|
|||
|
|
SubstratePositionResult.Read();
|
|||
|
|
DiePositionResult.Read();
|
|||
|
|
SubstrateHeightMeasureResult.Read();
|
|||
|
|
DieRecheckResult.Read();
|
|||
|
|
|
|||
|
|
// 3. 首页运行数据
|
|||
|
|
DashboardState.Read();
|
|||
|
|
|
|||
|
|
// 4. 准备区状态
|
|||
|
|
PreparationAreaState.Read();
|
|||
|
|
|
|||
|
|
// 5. 当前芯片使用位状态
|
|||
|
|
CurrentChipState.Read();
|
|||
|
|
|
|||
|
|
// 6. 自动流程运行态
|
|||
|
|
AutoProductionRuntimeState.Read();
|
|||
|
|
|
|||
|
|
// 后续如果有其他结果类(如 WaferMapResult),也在这里读取
|
|||
|
|
// WaferMapResult.Read();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private bool ShouldPersistFlowState(string workflowName)
|
|||
|
|
{
|
|||
|
|
return _machineState.CurrentMode == MachineMode.Auto ||
|
|||
|
|
string.Equals(workflowName, ProcessFlowName.AutoProduction, StringComparison.OrdinalIgnoreCase);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|