using MaxwellFramework.Core.Attributes; using MainShell.Common; using MainShell.ProcessResult; using MW.WorkFlow; using System; using System.Threading.Tasks; namespace MainShell.Process { [Singleton] public class DieTransferMotionService { private readonly AutoProductionRuntimeStateService _autoProductionRuntimeStateService; private readonly IDieTransferPathGenerator _dieTransferPathGenerator; public DieTransferMotionService(AutoProductionRuntimeStateService autoProductionRuntimeStateService, IDieTransferPathGenerator dieTransferPathGenerator) { _autoProductionRuntimeStateService = autoProductionRuntimeStateService ?? throw new ArgumentNullException(nameof(autoProductionRuntimeStateService)); _dieTransferPathGenerator = dieTransferPathGenerator ?? throw new ArgumentNullException(nameof(dieTransferPathGenerator)); } public async Task ExecuteAsync(WorkflowContext context, ActivityControl activityControl) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (activityControl == null) { throw new ArgumentNullException(nameof(activityControl)); } TryGeneratePathPlan(context); for (var i = 0; i < 20; i++) { activityControl.ThrowIfCancellationRequested(); await activityControl.CheckPauseAsync().ConfigureAwait(false); await Task.Delay(100, activityControl.CancellationToken).ConfigureAwait(false); } DieTransferDecisionResult decisionResult = ResolveDecisionResult(context); context.SetData(WorkflowContextKeys.DieTransferDecisionResult, decisionResult); context.SetRoute(WorkflowContextKeys.AutoProductionRoute, decisionResult.SuggestedRoute); bool hasCurrentChipStateService = context.TryGetData(WorkflowContextKeys.CurrentChipStateService, out CurrentChipStateService currentChipStateService) && currentChipStateService != null; if (decisionResult.SuggestedRoute == AutoProductionRoute.ChipExhausted || decisionResult.SuggestedRoute == AutoProductionRoute.BothExhausted) { context.SetData(WorkflowContextKeys.PendingChipLoad, true); context.SetData(WorkflowContextKeys.CurrentChipState, CurrentChipLifecycleState.PendingUnload); if (hasCurrentChipStateService) { currentChipStateService.SetState(CurrentChipLifecycleState.PendingUnload); } } else { context.SetData(WorkflowContextKeys.PendingChipLoad, false); context.SetData(WorkflowContextKeys.CurrentChipState, CurrentChipLifecycleState.InUse); if (hasCurrentChipStateService) { currentChipStateService.SetState(CurrentChipLifecycleState.InUse); } } if (decisionResult.IsSubstrateComplete) { context.SetData(WorkflowContextKeys.SubstrateProcessState, SubstrateLifecycleState.Complete); } else { context.SetData(WorkflowContextKeys.SubstrateProcessState, SubstrateLifecycleState.InProcess); } SyncRuntimeStateToContext(context); } public DieTransferPathPlan GeneratePathPlan(DieTransferPathRequest request) { return _dieTransferPathGenerator.Generate(request); } private DieTransferDecisionResult ResolveDecisionResult(WorkflowContext context) { bool needsRecheck = ConsumeBooleanFlag(context, WorkflowContextKeys.TransferNeedsRecheck) || _autoProductionRuntimeStateService.ConsumeTransferNeedsRecheck(); bool explicitChipExhausted = ConsumeBooleanFlag(context, WorkflowContextKeys.TransferChipExhausted) || _autoProductionRuntimeStateService.ConsumeTransferChipExhausted(); if (needsRecheck) { return CreateDecisionFromRoute(AutoProductionRoute.Recheck); } AutoProductionRoute autoRoute; if (context.TryGetRoute(WorkflowContextKeys.AutoProductionRoute, out autoRoute)) { if (autoRoute == AutoProductionRoute.Recheck) { return CreateDecisionFromRoute(autoRoute); } } DieTransferRoute legacyRoute; if (context.TryGetRoute(WorkflowContextKeys.DieTransferRoute, out legacyRoute) && legacyRoute == DieTransferRoute.Recheck) { return CreateDecisionFromRoute(AutoProductionRoute.Recheck); } bool isSubstrateComplete = UpdateSubstrateProgress(context); bool isChipExhausted = explicitChipExhausted || UpdateCurrentChipBudget(context); if (isSubstrateComplete && isChipExhausted) { return CreateDecisionFromRoute(AutoProductionRoute.BothExhausted); } if (isSubstrateComplete) { return CreateDecisionFromRoute(AutoProductionRoute.SubstrateComplete); } if (isChipExhausted) { return CreateDecisionFromRoute(AutoProductionRoute.ChipExhausted); } return CreateDecisionFromRoute(AutoProductionRoute.ContinueCurrentSubstrate); } private void TryGeneratePathPlan(WorkflowContext context) { DieTransferPathRequest pathRequest; if (!context.TryGetData(WorkflowContextKeys.DieTransferPathRequest, out pathRequest) || pathRequest == null) { return; } DieTransferPathPlan pathPlan = _dieTransferPathGenerator.Generate(pathRequest); context.SetData(WorkflowContextKeys.DieTransferPathPlan, pathPlan); } private bool UpdateSubstrateProgress(WorkflowContext context) { if (_autoProductionRuntimeStateService.CurrentSubstratePendingCount <= 0) { return false; } return _autoProductionRuntimeStateService.ConsumeSubstrateTarget(); } private bool UpdateCurrentChipBudget(WorkflowContext context) { if (_autoProductionRuntimeStateService.CurrentChipRemainingCount <= 0) { return false; } return _autoProductionRuntimeStateService.ConsumeCurrentChip(); } private static bool ConsumeBooleanFlag(WorkflowContext context, string key) { bool flagValue; if (!context.TryGetData(key, out flagValue) || !flagValue) { return false; } context.SetData(key, false); return true; } private void SyncRuntimeStateToContext(WorkflowContext context) { context.SetData(WorkflowContextKeys.CurrentSubstratePendingCount, _autoProductionRuntimeStateService.CurrentSubstratePendingCount); context.SetData(WorkflowContextKeys.CurrentSubstrateProcessedCount, _autoProductionRuntimeStateService.CurrentSubstrateProcessedCount); context.SetData(WorkflowContextKeys.CurrentChipRemainingCount, _autoProductionRuntimeStateService.CurrentChipRemainingCount); context.SetData(WorkflowContextKeys.TransferNeedsRecheck, _autoProductionRuntimeStateService.TransferNeedsRecheck); context.SetData(WorkflowContextKeys.TransferChipExhausted, _autoProductionRuntimeStateService.TransferChipExhausted); } private static DieTransferDecisionResult CreateDecisionFromRoute(AutoProductionRoute route) { DieTransferDecisionResult decisionResult = new DieTransferDecisionResult(); decisionResult.SuggestedRoute = route; decisionResult.NeedsRecheck = route == AutoProductionRoute.Recheck; decisionResult.IsChipExhausted = route == AutoProductionRoute.ChipExhausted || route == AutoProductionRoute.BothExhausted; decisionResult.IsSubstrateComplete = route == AutoProductionRoute.SubstrateComplete || route == AutoProductionRoute.BothExhausted; return decisionResult; } } }