添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
using MainShell.Common;
|
||||
using MainShell.Log;
|
||||
using MainShell.ProcessResult;
|
||||
using MW.WorkFlow;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Process
|
||||
{
|
||||
public class SubstrateHeightMeasureActivity : ActivityAbstractBase
|
||||
{
|
||||
private readonly SubstrateHeightMeasureService _substrateHeightMeasureService;
|
||||
|
||||
public SubstrateHeightMeasureActivity(string name, SubstrateHeightMeasureService substrateHeightMeasureService)
|
||||
: base(name)
|
||||
{
|
||||
_substrateHeightMeasureService = substrateHeightMeasureService ?? throw new ArgumentNullException(nameof(substrateHeightMeasureService));
|
||||
}
|
||||
|
||||
protected override async Task<ActivityResult> OnExecuteAsync(WorkflowContext context, ActivityControl activityControl)
|
||||
{
|
||||
await _substrateHeightMeasureService.ExecuteAsync(context, activityControl).ConfigureAwait(false);
|
||||
|
||||
SubstrateHeightMeasureProcessResult result = context.GetData<SubstrateHeightMeasureProcessResult>(WorkflowContextKeys.SubstrateHeightMeasureResult);
|
||||
if (result == null || !result.IsSuccess)
|
||||
{
|
||||
MessageKey failureMessageKey = result != null && result.ErrorMessageKey != MessageKey.None
|
||||
? result.ErrorMessageKey
|
||||
: MessageKey.ProcessSubstrateHeightMeasureFailedWithReason;
|
||||
|
||||
object[] failureMessageArguments = result != null
|
||||
? ConvertToObjectArray(result.ErrorMessageArguments)
|
||||
: new object[] { LanguageResourceHelper.GetString(MessageKey.CommonUnknownError) };
|
||||
|
||||
string errorMessage = result != null && !string.IsNullOrWhiteSpace(result.ErrorMessage)
|
||||
? result.ErrorMessage
|
||||
: LanguageResourceHelper.Format(failureMessageKey, failureMessageArguments);
|
||||
|
||||
LogManager.LogProcessError($"SubstrateHeightMeasure activity failed: {errorMessage}");
|
||||
return Fail(context, failureMessageKey, failureMessageArguments);
|
||||
}
|
||||
|
||||
context.SetData(WorkflowContextKeys.SubstrateProcessState, SubstrateLifecycleState.HeightMeasured);
|
||||
return ActivityResult.Success;
|
||||
}
|
||||
|
||||
private static object[] ConvertToObjectArray(string[] arguments)
|
||||
{
|
||||
return arguments == null ? Array.Empty<object>() : arguments.Cast<object>().ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
using MainShell.Common;
|
||||
using MainShell.HeightMeasure.Model;
|
||||
using MainShell.HeightMeasure.Service;
|
||||
using MainShell.Log;
|
||||
using MainShell.Models;
|
||||
using MainShell.ProcessResult;
|
||||
using MainShell.Recipe.Models;
|
||||
using MainShell.Recipe.Models.SubstrateParameter;
|
||||
using MW.WorkFlow;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Process
|
||||
{
|
||||
public class SubstrateHeightMeasureService
|
||||
{
|
||||
private readonly IHeightMeasure _heightMeasure;
|
||||
private readonly HeightMeasureMotionService _heightMeasureMotionService;
|
||||
|
||||
public SubstrateHeightMeasureService(IHeightMeasure heightMeasure, HeightMeasureMotionService heightMeasureMotionService)
|
||||
{
|
||||
_heightMeasure = heightMeasure ?? throw new ArgumentNullException(nameof(heightMeasure));
|
||||
_heightMeasureMotionService = heightMeasureMotionService ?? throw new ArgumentNullException(nameof(heightMeasureMotionService));
|
||||
}
|
||||
|
||||
public async Task ExecuteAsync(WorkflowContext context, ActivityControl activityControl)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (activityControl == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(activityControl));
|
||||
}
|
||||
|
||||
RecipeManager recipeManager = context.GetData<RecipeManager>(WorkflowContextKeys.RecipeManager);
|
||||
ProcessResultManager processResultManager = context.GetData<ProcessResultManager>(WorkflowContextKeys.ProcessResultManager);
|
||||
SubstrateRecipe substrateRecipe = GetCurrentRecipe(recipeManager);
|
||||
IList<SubstrateHeightMeasurePoint> points = GetAvailablePoints(substrateRecipe);
|
||||
SubstrateHeightMeasureProcessResult processResult = InitializeProcessResult(processResultManager, substrateRecipe.RecipeName);
|
||||
|
||||
try
|
||||
{
|
||||
LogManager.LogProcessInfo($"SubstrateHeightMeasure: start. Recipe={substrateRecipe.RecipeName}, PointCount={points.Count}");
|
||||
|
||||
for (int index = 0; index < points.Count; index++)
|
||||
{
|
||||
SubstrateHeightMeasurePoint point = points[index];
|
||||
string pointName = GetPointName(point, index);
|
||||
|
||||
await CheckCancellationAndPauseAsync(activityControl).ConfigureAwait(false);
|
||||
|
||||
double positionX;
|
||||
double positionY;
|
||||
ResolveMeasurePosition(substrateRecipe, point, pointName, out positionX, out positionY);
|
||||
|
||||
LogManager.LogProcessDebug($"SubstrateHeightMeasure: moving to point[{index}] '{pointName}', X={positionX:F4}, Y={positionY:F4}");
|
||||
_heightMeasureMotionService.MoveWaferMeasurePose(positionX, positionY);
|
||||
|
||||
double heightValue = _heightMeasure.GetDistance();
|
||||
processResult.PointResults.Add(new SubstrateHeightMeasurePointResult
|
||||
{
|
||||
PointName = pointName,
|
||||
RowIndex = point.RowIndex,
|
||||
ColumnIndex = point.ColumnIndex,
|
||||
PositionX = positionX,
|
||||
PositionY = positionY,
|
||||
HeightValue = heightValue
|
||||
});
|
||||
|
||||
LogManager.LogProcessInfo($"SubstrateHeightMeasure: point[{index}] '{pointName}' measured height={heightValue:F4}");
|
||||
}
|
||||
|
||||
processResult.IsSuccess = true;
|
||||
processResult.ErrorMessage = null;
|
||||
processResult.ErrorMessageKey = MessageKey.None;
|
||||
processResult.ErrorMessageArguments = Array.Empty<string>();
|
||||
LogManager.LogProcessInfo($"SubstrateHeightMeasure: completed. Recipe={substrateRecipe.RecipeName}, PointCount={processResult.PointResults.Count}");
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
processResult.IsSuccess = false;
|
||||
processResult.ErrorMessage = null;
|
||||
processResult.ErrorMessageKey = MessageKey.None;
|
||||
processResult.ErrorMessageArguments = Array.Empty<string>();
|
||||
LogManager.LogProcessInfo("SubstrateHeightMeasure: operation canceled.");
|
||||
throw;
|
||||
}
|
||||
catch (LocalizedProcessException ex)
|
||||
{
|
||||
processResult.IsSuccess = false;
|
||||
processResult.ErrorMessageKey = ex.FailureMessageKey;
|
||||
processResult.ErrorMessageArguments = ex.FailureMessageArguments;
|
||||
processResult.ErrorMessage = ex.Message;
|
||||
LogManager.LogProcessError($"SubstrateHeightMeasure: {ex.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
processResult.IsSuccess = false;
|
||||
processResult.ErrorMessageKey = MessageKey.ProcessSubstrateHeightMeasureFailedWithReason;
|
||||
processResult.ErrorMessageArguments = new string[] { ex.Message ?? string.Empty };
|
||||
processResult.ErrorMessage = LanguageResourceHelper.Format(
|
||||
processResult.ErrorMessageKey,
|
||||
LocalizedProcessException.ConvertArguments(processResult.ErrorMessageArguments));
|
||||
LogManager.LogProcessError($"SubstrateHeightMeasure: {processResult.ErrorMessage}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
WriteResultToContext(context, processResultManager, processResult);
|
||||
}
|
||||
}
|
||||
|
||||
private static SubstrateRecipe GetCurrentRecipe(RecipeManager recipeManager)
|
||||
{
|
||||
if (recipeManager == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(recipeManager));
|
||||
}
|
||||
|
||||
if (recipeManager.CurrentSubstrateRecipe == null)
|
||||
{
|
||||
throw new LocalizedProcessException(
|
||||
MessageKey.ProcessSubstrateHeightMeasureRecipeNotLoaded,
|
||||
Array.Empty<string>());
|
||||
}
|
||||
|
||||
return recipeManager.CurrentSubstrateRecipe;
|
||||
}
|
||||
|
||||
private static IList<SubstrateHeightMeasurePoint> GetAvailablePoints(SubstrateRecipe substrateRecipe)
|
||||
{
|
||||
if (substrateRecipe == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(substrateRecipe));
|
||||
}
|
||||
|
||||
if (substrateRecipe.HeightMeasureSetting == null || substrateRecipe.HeightMeasureSetting.Points == null)
|
||||
{
|
||||
throw new LocalizedProcessException(
|
||||
MessageKey.ProcessSubstrateHeightMeasureSettingMissing,
|
||||
Array.Empty<string>());
|
||||
}
|
||||
|
||||
List<SubstrateHeightMeasurePoint> points = new List<SubstrateHeightMeasurePoint>();
|
||||
foreach (SubstrateHeightMeasurePoint point in substrateRecipe.HeightMeasureSetting.Points)
|
||||
{
|
||||
if (point != null)
|
||||
{
|
||||
points.Add(point);
|
||||
}
|
||||
}
|
||||
|
||||
if (points.Count == 0)
|
||||
{
|
||||
throw new LocalizedProcessException(
|
||||
MessageKey.ProcessSubstrateHeightMeasureNoPoints,
|
||||
Array.Empty<string>());
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
private static SubstrateHeightMeasureProcessResult InitializeProcessResult(ProcessResultManager processResultManager, string recipeName)
|
||||
{
|
||||
if (processResultManager == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(processResultManager));
|
||||
}
|
||||
|
||||
SubstrateHeightMeasureProcessResult processResult = processResultManager.SubstrateHeightMeasureResult;
|
||||
processResult.IsSuccess = false;
|
||||
processResult.RecipeName = recipeName;
|
||||
processResult.ErrorMessage = null;
|
||||
processResult.ErrorMessageKey = MessageKey.None;
|
||||
processResult.ErrorMessageArguments = Array.Empty<string>();
|
||||
processResult.PointResults.Clear();
|
||||
return processResult;
|
||||
}
|
||||
|
||||
private static async Task CheckCancellationAndPauseAsync(ActivityControl activityControl)
|
||||
{
|
||||
activityControl.ThrowIfCancellationRequested();
|
||||
await activityControl.CheckPauseAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static void ResolveMeasurePosition(SubstrateRecipe substrateRecipe, SubstrateHeightMeasurePoint point, string pointName, out double positionX, out double positionY)
|
||||
{
|
||||
if (substrateRecipe == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(substrateRecipe));
|
||||
}
|
||||
|
||||
if (point == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(point));
|
||||
}
|
||||
|
||||
if (substrateRecipe.HeightMeasureSetting != null && substrateRecipe.HeightMeasureSetting.Mode == SubstrateHeightMeasureMode.RowColumnOffset)
|
||||
{
|
||||
if (substrateRecipe.SubstrateInfo == null || substrateRecipe.SubstrateInfo.PitchX <= 0 || substrateRecipe.SubstrateInfo.PitchY <= 0)
|
||||
{
|
||||
throw new LocalizedProcessException(
|
||||
MessageKey.ProcessSubstrateHeightMeasurePointPositionInvalid,
|
||||
pointName);
|
||||
}
|
||||
|
||||
if (point.RowIndex <= 0 || point.ColumnIndex <= 0)
|
||||
{
|
||||
throw new LocalizedProcessException(
|
||||
MessageKey.ProcessSubstrateHeightMeasurePointPositionInvalid,
|
||||
pointName);
|
||||
}
|
||||
|
||||
MPoint commonOffset = substrateRecipe.HeightMeasureSetting.CommonOffsetCompensation ?? new MPoint();
|
||||
MPoint pointOffset = point.OffsetCompensation ?? new MPoint();
|
||||
positionX = (point.ColumnIndex - 1) * substrateRecipe.SubstrateInfo.PitchX + commonOffset.X + pointOffset.X;
|
||||
positionY = (point.RowIndex - 1) * substrateRecipe.SubstrateInfo.PitchY + commonOffset.Y + pointOffset.Y;
|
||||
return;
|
||||
}
|
||||
|
||||
if (point.TeachPosition == null)
|
||||
{
|
||||
throw new LocalizedProcessException(
|
||||
MessageKey.ProcessSubstrateHeightMeasurePointPositionInvalid,
|
||||
pointName);
|
||||
}
|
||||
|
||||
positionX = point.TeachPosition.X;
|
||||
positionY = point.TeachPosition.Y;
|
||||
}
|
||||
|
||||
private static string GetPointName(SubstrateHeightMeasurePoint point, int index)
|
||||
{
|
||||
if (point == null || string.IsNullOrWhiteSpace(point.PointName))
|
||||
{
|
||||
return $"Point{index + 1}";
|
||||
}
|
||||
|
||||
return point.PointName;
|
||||
}
|
||||
|
||||
private static void WriteResultToContext(
|
||||
WorkflowContext context,
|
||||
ProcessResultManager processResultManager,
|
||||
SubstrateHeightMeasureProcessResult processResult)
|
||||
{
|
||||
context.SetData(WorkflowContextKeys.SubstrateHeightMeasureResult, processResult);
|
||||
processResultManager.SaveSubstrateHeightMeasureResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using MW.WorkFlow;
|
||||
using MainShell.Common;
|
||||
|
||||
namespace MainShell.Process
|
||||
{
|
||||
public class SubstrateLoadActivity : ActivityAbstractBase
|
||||
{
|
||||
public SubstrateLoadActivity(string name) : base(name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override async Task<ActivityResult> OnExecuteAsync(WorkflowContext context, ActivityControl activityControl)
|
||||
{
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
activityControl.ThrowIfCancellationRequested();
|
||||
await activityControl.CheckPauseAsync();
|
||||
await Task.Delay(100, activityControl.CancellationToken);
|
||||
}
|
||||
|
||||
context.SetData(WorkflowContextKeys.SubstrateProcessState, SubstrateLifecycleState.Loaded);
|
||||
|
||||
return ActivityResult.Success;
|
||||
}
|
||||
protected override void PrepareExecute(WorkflowContext context, ActivityControl activityControl)
|
||||
{
|
||||
// Custom preparation logic before execution
|
||||
}
|
||||
protected override void AfterExecute(WorkflowContext context, ActivityControl activityControl)
|
||||
{
|
||||
// Custom cleanup logic after execution
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using MainShell.Common;
|
||||
using MainShell.Log;
|
||||
using MainShell.ProcessResult;
|
||||
using MW.WorkFlow;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Process
|
||||
{
|
||||
public class SubstratePositionActivity : ActivityAbstractBase
|
||||
{
|
||||
private readonly SubstratePositionMotionService _motionService;
|
||||
|
||||
public SubstratePositionActivity(string name, SubstratePositionMotionService motionService)
|
||||
: base(name)
|
||||
{
|
||||
_motionService = motionService ?? throw new ArgumentNullException(nameof(motionService));
|
||||
}
|
||||
|
||||
protected override async Task<ActivityResult> OnExecuteAsync(WorkflowContext context, ActivityControl activityControl)
|
||||
{
|
||||
await _motionService.ExecuteAsync(context, activityControl).ConfigureAwait(false);
|
||||
|
||||
SubstratePositionProcessResult result = context.GetData<SubstratePositionProcessResult>(WorkflowContextKeys.SubstratePositionResult);
|
||||
if (result == null || !result.IsSuccess)
|
||||
{
|
||||
MessageKey failureMessageKey = result != null && result.ErrorMessageKey != MessageKey.None
|
||||
? result.ErrorMessageKey
|
||||
: MessageKey.ProcessSubstratePositionFailedWithReason;
|
||||
|
||||
object[] failureMessageArguments = result != null
|
||||
? ConvertToObjectArray(result.ErrorMessageArguments)
|
||||
: new object[] { LanguageResourceHelper.GetString(MessageKey.CommonUnknownError) };
|
||||
|
||||
string errorMsg = result != null && !string.IsNullOrWhiteSpace(result.ErrorMessage)
|
||||
? result.ErrorMessage
|
||||
: LanguageResourceHelper.Format(failureMessageKey, failureMessageArguments);
|
||||
|
||||
LogManager.LogSysError($"SubstratePosition activity failed: {errorMsg}");
|
||||
return Fail(context, failureMessageKey, failureMessageArguments);
|
||||
}
|
||||
|
||||
context.SetData(WorkflowContextKeys.SubstrateProcessState, SubstrateLifecycleState.Positioned);
|
||||
|
||||
return ActivityResult.Success;
|
||||
}
|
||||
|
||||
private static object[] ConvertToObjectArray(string[] arguments)
|
||||
{
|
||||
return arguments == null ? Array.Empty<object>() : arguments.Cast<object>().ToArray();
|
||||
}
|
||||
|
||||
protected override void PrepareExecute(WorkflowContext context, ActivityControl activityControl)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void AfterExecute(WorkflowContext context, ActivityControl activityControl)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
using MainShell.Common;
|
||||
using MainShell.Log;
|
||||
using MainShell.Motion;
|
||||
using MainShell.ProcessResult;
|
||||
using MainShell.Recipe.Models;
|
||||
using MainShell.Recipe.Models.SubstrateParameter;
|
||||
using MW.WorkFlow;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.Process
|
||||
{
|
||||
public class SubstratePositionMotionService
|
||||
{
|
||||
private readonly ApproachAlignmentService _approachAlignmentService;
|
||||
|
||||
public SubstratePositionMotionService(ApproachAlignmentService approachAlignmentService)
|
||||
{
|
||||
_approachAlignmentService = approachAlignmentService ?? throw new ArgumentNullException(nameof(approachAlignmentService));
|
||||
}
|
||||
|
||||
public async Task ExecuteAsync(WorkflowContext context, ActivityControl activityControl)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (activityControl == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(activityControl));
|
||||
}
|
||||
|
||||
RecipeManager recipeManager = GetRecipeManager(context);
|
||||
ProcessResultManager processResultManager = GetProcessResultManager(context);
|
||||
SubstrateRecipe substrateRecipe = GetCurrentRecipe(recipeManager);
|
||||
List<MarkData> enabledMarks = GetEnabledMarks(substrateRecipe);
|
||||
SubstratePositionProcessResult processResult = InitializeProcessResult(processResultManager, enabledMarks.Count);
|
||||
|
||||
try
|
||||
{
|
||||
LogManager.LogInfo($"SubstratePosition: start mark positioning. Total enabled marks: {enabledMarks.Count}");
|
||||
|
||||
for (int i = 0; i < enabledMarks.Count; i++)
|
||||
{
|
||||
MarkData markData = enabledMarks[i];
|
||||
string markName = string.IsNullOrWhiteSpace(markData?.TemplateName) ? $"Mark_{i}" : markData.TemplateName;
|
||||
|
||||
await CheckCancellationAndPauseAsync(activityControl).ConfigureAwait(false);
|
||||
|
||||
LogManager.LogInfo($"SubstratePosition: executing approach alignment for mark[{i}] '{markName}'");
|
||||
ApproachAlignmentResult alignmentResult = await ExecuteApproachAlignmentAsync(markData, activityControl).ConfigureAwait(false);
|
||||
|
||||
if (!alignmentResult.Succeeded)
|
||||
{
|
||||
string reason = alignmentResult.Message ?? string.Empty;
|
||||
string errorMsg = $"SubstratePosition: approach alignment failed for mark[{i}] '{markName}'. Reason: {reason}";
|
||||
LogManager.LogSysError(errorMsg);
|
||||
throw new LocalizedProcessException(
|
||||
MessageKey.ProcessSubstratePositionAlignmentFailedWithReason,
|
||||
new[] { markName, reason });
|
||||
}
|
||||
|
||||
Point recognizedPos = ExtractRecognizedPosition(alignmentResult, markData);
|
||||
processResult.MarkResults.Add(recognizedPos);
|
||||
processResult.RecognizedMarkCount++;
|
||||
|
||||
LogManager.LogInfo(
|
||||
string.Format(
|
||||
"SubstratePosition: mark[{0}] aligned successfully. Iterations: {1}. Position: ({2:F4}, {3:F4})",
|
||||
i,
|
||||
alignmentResult.CompletedIterations,
|
||||
recognizedPos.X,
|
||||
recognizedPos.Y));
|
||||
}
|
||||
|
||||
processResult.SubstrateAngle = CalculateSubstrateAngle(processResult.MarkResults);
|
||||
processResult.IsSuccess = true;
|
||||
processResult.ErrorMessage = null;
|
||||
processResult.ErrorMessageKey = MessageKey.None;
|
||||
processResult.ErrorMessageArguments = Array.Empty<string>();
|
||||
|
||||
LogManager.LogInfo(
|
||||
string.Format(
|
||||
"SubstratePosition: completed successfully. Recognized: {0}/{1}, Angle: {2:F6}",
|
||||
processResult.RecognizedMarkCount,
|
||||
processResult.AvailableMarkCount,
|
||||
processResult.SubstrateAngle));
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
processResult.IsSuccess = false;
|
||||
processResult.ErrorMessage = null;
|
||||
processResult.ErrorMessageKey = MessageKey.None;
|
||||
processResult.ErrorMessageArguments = Array.Empty<string>();
|
||||
LogManager.LogInfo("SubstratePosition: operation canceled.");
|
||||
throw;
|
||||
}
|
||||
catch (LocalizedProcessException ex)
|
||||
{
|
||||
processResult.IsSuccess = false;
|
||||
processResult.ErrorMessageKey = ex.FailureMessageKey;
|
||||
processResult.ErrorMessageArguments = ex.FailureMessageArguments;
|
||||
processResult.ErrorMessage = ex.Message;
|
||||
LogManager.LogSysError(ex.Message);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
processResult.IsSuccess = false;
|
||||
processResult.ErrorMessageKey = MessageKey.ProcessStepFailedWithReason;
|
||||
processResult.ErrorMessageArguments = new[] { ProcessFlowName.SubstratePositionFlow, ex.Message ?? string.Empty };
|
||||
processResult.ErrorMessage = LanguageResourceHelper.Format(
|
||||
processResult.ErrorMessageKey,
|
||||
LocalizedProcessException.ConvertArguments(processResult.ErrorMessageArguments));
|
||||
LogManager.LogSysError(processResult.ErrorMessage);
|
||||
}
|
||||
finally
|
||||
{
|
||||
WriteResultToContext(context, processResultManager, processResult);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ApproachAlignmentResult> ExecuteApproachAlignmentAsync(MarkData markData, ActivityControl activityControl)
|
||||
{
|
||||
if (markData == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(markData));
|
||||
}
|
||||
|
||||
List<ApproachAlignmentAxis> axes = new List<ApproachAlignmentAxis>
|
||||
{
|
||||
new ApproachAlignmentAxis("X", 0.1),
|
||||
new ApproachAlignmentAxis("Y", 0.1)
|
||||
};
|
||||
|
||||
ApproachAlignmentRequest request = new ApproachAlignmentRequest(axes)
|
||||
{
|
||||
MaxIterations = 5,
|
||||
MoveTimeoutMilliseconds = 30000,
|
||||
RecognitionTimeoutMilliseconds = 10000
|
||||
};
|
||||
|
||||
return await _approachAlignmentService
|
||||
.ApproachAlignmentAsync(request, activityControl.CancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static Point ExtractRecognizedPosition(ApproachAlignmentResult alignmentResult, MarkData markData)
|
||||
{
|
||||
if (alignmentResult == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(alignmentResult));
|
||||
}
|
||||
|
||||
if (alignmentResult.FinalAxisPositions == null ||
|
||||
!alignmentResult.FinalAxisPositions.TryGetValue("X", out var x) ||
|
||||
!alignmentResult.FinalAxisPositions.TryGetValue("Y", out var y))
|
||||
{
|
||||
throw new LocalizedProcessException(
|
||||
MessageKey.ProcessSubstratePositionAlignmentFailedWithReason,
|
||||
new[]
|
||||
{
|
||||
string.IsNullOrWhiteSpace(markData?.TemplateName) ? string.Empty : markData.TemplateName,
|
||||
"Recognized position is missing X or Y axis data."
|
||||
});
|
||||
}
|
||||
|
||||
return new Point(x, y);
|
||||
}
|
||||
|
||||
private static async Task CheckCancellationAndPauseAsync(ActivityControl activityControl)
|
||||
{
|
||||
activityControl.ThrowIfCancellationRequested();
|
||||
await activityControl.CheckPauseAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static RecipeManager GetRecipeManager(WorkflowContext context)
|
||||
{
|
||||
return context.GetData<RecipeManager>(WorkflowContextKeys.RecipeManager);
|
||||
}
|
||||
|
||||
private static ProcessResultManager GetProcessResultManager(WorkflowContext context)
|
||||
{
|
||||
return context.GetData<ProcessResultManager>(WorkflowContextKeys.ProcessResultManager);
|
||||
}
|
||||
|
||||
private static SubstrateRecipe GetCurrentRecipe(RecipeManager recipeManager)
|
||||
{
|
||||
if (recipeManager == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(recipeManager));
|
||||
}
|
||||
|
||||
if (recipeManager.CurrentSubstrateRecipe == null)
|
||||
{
|
||||
throw new LocalizedProcessException(
|
||||
MessageKey.ProcessSubstratePositionRecipeNotLoaded,
|
||||
Array.Empty<string>());
|
||||
}
|
||||
|
||||
return recipeManager.CurrentSubstrateRecipe;
|
||||
}
|
||||
|
||||
private static List<MarkData> GetEnabledMarks(SubstrateRecipe substrateRecipe)
|
||||
{
|
||||
if (substrateRecipe?.SubtrateMarkParameterInfo?.MarkDatas == null)
|
||||
{
|
||||
throw new LocalizedProcessException(
|
||||
MessageKey.ProcessSubstratePositionMarkParameterMissing,
|
||||
Array.Empty<string>());
|
||||
}
|
||||
|
||||
List<MarkData> enabledMarks = substrateRecipe.SubtrateMarkParameterInfo.MarkDatas
|
||||
.Where(mark => mark != null && mark.IsEnabled)
|
||||
.ToList();
|
||||
|
||||
if (enabledMarks.Count == 0)
|
||||
{
|
||||
throw new LocalizedProcessException(
|
||||
MessageKey.ProcessSubstratePositionNoEnabledMarks,
|
||||
Array.Empty<string>());
|
||||
}
|
||||
|
||||
return enabledMarks;
|
||||
}
|
||||
|
||||
private static SubstratePositionProcessResult InitializeProcessResult(ProcessResultManager processResultManager, int availableMarkCount)
|
||||
{
|
||||
if (processResultManager == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(processResultManager));
|
||||
}
|
||||
|
||||
SubstratePositionProcessResult processResult = processResultManager.SubstratePositionResult;
|
||||
processResult.IsSuccess = false;
|
||||
processResult.AvailableMarkCount = availableMarkCount;
|
||||
processResult.RecognizedMarkCount = 0;
|
||||
processResult.ErrorMessage = null;
|
||||
processResult.ErrorMessageKey = MessageKey.None;
|
||||
processResult.ErrorMessageArguments = Array.Empty<string>();
|
||||
processResult.SubstrateAngle = 0;
|
||||
processResult.MarkResults.Clear();
|
||||
return processResult;
|
||||
}
|
||||
|
||||
private static double CalculateSubstrateAngle(List<Point> markResults)
|
||||
{
|
||||
if (markResults == null || markResults.Count < 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
double centroidX = markResults.Average(point => point.X);
|
||||
double centroidY = markResults.Average(point => point.Y);
|
||||
|
||||
double sumXX = 0;
|
||||
double sumYY = 0;
|
||||
double sumXY = 0;
|
||||
|
||||
foreach (Point point in markResults)
|
||||
{
|
||||
double dx = point.X - centroidX;
|
||||
double dy = point.Y - centroidY;
|
||||
sumXX += dx * dx;
|
||||
sumYY += dy * dy;
|
||||
sumXY += dx * dy;
|
||||
}
|
||||
|
||||
if (Math.Abs(sumXX) < 1e-9 && Math.Abs(sumYY) < 1e-9 && Math.Abs(sumXY) < 1e-9)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
double angleRadians = 0.5 * Math.Atan2(2 * sumXY, sumXX - sumYY);
|
||||
return angleRadians * 180.0 / Math.PI;
|
||||
}
|
||||
|
||||
private static void WriteResultToContext(
|
||||
WorkflowContext context,
|
||||
ProcessResultManager processResultManager,
|
||||
SubstratePositionProcessResult processResult)
|
||||
{
|
||||
context.SetData(WorkflowContextKeys.SubstratePositionResult, processResult);
|
||||
processResultManager.SaveSubstratePositionResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using MainShell.Common;
|
||||
using MW.WorkFlow;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Process
|
||||
{
|
||||
public class SubstrateUnloadActivity : ActivityAbstractBase
|
||||
{
|
||||
public SubstrateUnloadActivity(string name)
|
||||
: base(name)
|
||||
{
|
||||
}
|
||||
|
||||
protected override async Task<ActivityResult> OnExecuteAsync(WorkflowContext context, ActivityControl activityControl)
|
||||
{
|
||||
context.SetData(WorkflowContextKeys.SubstrateProcessState, SubstrateLifecycleState.Unloading);
|
||||
|
||||
for (int index = 0; index < 10; index++)
|
||||
{
|
||||
activityControl.ThrowIfCancellationRequested();
|
||||
await activityControl.CheckPauseAsync().ConfigureAwait(false);
|
||||
await Task.Delay(100, activityControl.CancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
context.SetData(WorkflowContextKeys.SubstrateProcessState, SubstrateLifecycleState.NotLoaded);
|
||||
return ActivityResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user