2026-01-26 18:56:53 +09:00

734 lines
30 KiB
C#

/*
* Copyright (c) 2025 LG Electronics Inc.
* SPDX-License-Identifier: LicenseRef-LGE-Proprietary
*/
using Aurora.Api;
using Aurora.Api.Devices;
using VisionCommon;
using VisionSequence.Pattern;
using VisionAligner;
using Hermes;
using VisionDirector;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Contexts;
using VisionCommon.DB.Align;
using VisionCommon.DB;
using System;
namespace VisionSequence.Aligner {
/// <summary>
/// 얼라인 공정 시퀀스 파라미터
/// </summary>
public class AlignProcSeqParams : SeqParamsBase {
/// <summary>얼라인 키 정보</summary>
public AlignInfo AlignInfo { get; set; }
/// <summary>FOV별로 이동시킬 절대위치</summary>
public Dictionary<eFovId, Position> FovPositions { get; set; }
/// <summary>메인 화면 타입</summary>
public eDisplayType DisplayType { get; set; }
/// <summary>
/// 얼라인 재시도(Retry) 카운트 초기화 플래그
/// 1) 비전에서 Move와 Retry를 처리할 경우 [True]
/// 2) 제어에서 Move와 Retry를 처리하면서, 얼라인 시퀀스를 신규 호출한 경우 [True]
/// 3) 제어에서 Move와 Retry를 처리하면서, Retry로 얼라인 시퀀스를 다시 호출한 경우 [False]
/// </summary>
public bool AlignCntClear { get; set; }
/// <summary>
/// DB 사용시에만 할당해서 사용
/// </summary>
internal VisionAlignDB AlignDB { get; set; }
/// <summary>
/// 얼라인 시퀀스 파라미터를 얻어온다.
/// </summary>
/// <param name="alignInfo">얼라인 키 정보</param>
/// <param name="fovPositions">FOV별로 이동시킬 절대위치. null일 경우, 자동으로 Adapter에 정의된 티칭위치로 이동</param>
/// <param name="displayType">메인 화면 타입</param>
/// <param name="alignCntClear">얼라인 횟수</param>
/// <param name="seqMode">시퀀스 모드</param>
public AlignProcSeqParams(
AlignInfo alignInfo,
Dictionary<eFovId, Position> fovPositions = null,
eDisplayType displayType = eDisplayType.Main_1,
bool alignCntClear = true,
eSeqMode seqMode = eSeqMode.Auto) : base(seqMode) {
this.AlignInfo = alignInfo;
this.FovPositions = fovPositions;
this.DisplayType = displayType;
this.AlignCntClear = alignCntClear;
AlignDB = VisionSettingManager.VisionSetting.UseDBService ? new VisionAlignDB(alignInfo, seqMode) : null;
}
}
/// <summary>
/// 얼라인 공정 시퀀스
/// </summary>
public class AlignProcSeq : SubSeqBase {
private readonly Logger LOG = new Logger(typeof(AlignProcSeq).Name);
private Logger _VisionLog = new Logger(typeof(AlignProcSeq).Name, VisionKeys.LogKey);
private TactTimeChecker _TactTimeChecker;
private VisionAligner.Aligner _Aligner;
private AlignRecipe _AlignRecipe;
private SubSysInfo _SubSysInfo;
private AlignProcSeqParams _Params;
private CsvManager _CsvManager = new CsvManager();
private ImageManager _ImageManager = new ImageManager();
private string _SeqName;
#region Sequence Id
private const string SEQ_ID_INIT = "INIT";
private const string SEQ_ID_MOVE_FIRST_TEACHING_POS = "SEQ_ID_MOVE_FIRST_TEACHING_POS";
// Dry Run
private const string SEQ_CHECK_DRY_RUN = "CHECK_DRY_RUN";
private const string SEQ_ID_SET_DRY_RUN_SEQ_PARAMS = "SET_DRY_RUN_SEQ_PARAMS";
private const string SEQ_ID_DRY_RUN_SEQ = "DRY_RUN_SEQ";
private const string SEQ_ID_DRY_RUN_UPDATE_UI = "DRY_RUN_UPDATE_UI";
private const string SEQ_ID_CLEAR = "CLEAR";
private const string SEQ_ID_CHECK_PROC_PATTERN = "SEQ_ID_CHECK_PROC_PATTERN";
private const string SEQ_ID_UNDEFINED_PATTERN_NG = "SEQ_ID_UNDEFINED_PATTERN_NG";
private const string SEQ_ID_SET_ALIGN_SEQ_PARAMS = "SET_ALIGN_SEQ_PARAMS";
private const string SEQ_ID_ALIGN_SEQ = "ALIGN_SEQ";
private const string SEQ_ID_CHECK_STATUS = "CHECK_STATUS";
private const string SEQ_ID_MARK_NG = "MARK_NG";
private const string SEQ_ID_DISTANCE_NG = "DISTANCE_NG";
private const string SEQ_ID_ALIGN_LIMIT_NG = "ALIGN_LIMIT_NG";
private const string SEQ_ID_RETRY_COUNT_NG = "RETRY_COUNT_NG";
private const string SEQ_ID_ALIGN_RESULT_NULL = "ALIGN_RESULT_NULL";
private const string SEQ_ID_FORK = "FORK";
private const string SEQ_ID_APPLY_OFFSET = "APPLY_OFFSET";
private const string SEQ_ID_CHECK_MOVE_ENABLED = "CHECK_MOVE_ENABLED";
private const string SEQ_ID_MOVE_DELTA = "MOVE_DELTA";
private const string SEQ_ID_MOVE_FINISHED = "MOVE_FINISHED";
private const string SEQ_ID_UPDATE_UI = "UPDATE_UI";
private const string SEQ_ID_SAVE_CSV = "SAVE_CSV";
private const string SEQ_ID_SAVE_SCREENSHOT = "SAVE_SCREENSHOT";
private const string SEQ_ID_JOIN = "JOIN";
private const string SEQ_ID_CHECK_RETRY = "CHECK_RETRY";
private const string SEQ_ID_SEQ_COMPLETE = "SEQ_COMPLETE";
#endregion
/// <summary>
/// 생성자
/// </summary>
/// <param name="seqName">시퀀스 이름</param>
/// <param name="alignInfo">시퀀스 키 정보</param>
public AlignProcSeq(string seqName, AlignInfo alignInfo) {
_SeqName = seqName;
_AlignRecipe = VisionRecipeManager.GetAlignRecipe(alignInfo);
_SubSysInfo = alignInfo?.ToSubSysInfo();
}
private void SetActions(SequenceBuilder sb) {
SequenceBuilder dryRunSeqBuilder = SubSeqManager.CreateSubSeqBuilder(new AlignSeq_DryRun(), typeof(AlignSeq_DryRun).Name);
SequenceBuilder alignSeqBuilder = SubSeqManager.CreateSubSeqBuilder(new AlignSubSeq(), typeof(AlignSubSeq).Name);
sb.AddAction(SEQ_ID_INIT, Init);
sb.AddAction(SEQ_ID_MOVE_FIRST_TEACHING_POS, MoveFirstTeachingPos);
// Dry Run
sb.AddDecision(SEQ_CHECK_DRY_RUN, CheckDryRun);
sb.AddAction(SEQ_ID_SET_DRY_RUN_SEQ_PARAMS, SetDryRunSeqParams);
sb.AddSubsequence(SEQ_ID_DRY_RUN_SEQ, dryRunSeqBuilder);
sb.AddAction(SEQ_ID_DRY_RUN_UPDATE_UI, UpdateUI);
sb.AddAction(SEQ_ID_CLEAR, Clear);
sb.AddDecision(SEQ_ID_CHECK_PROC_PATTERN, CheckProcPattern);
sb.AddAction(SEQ_ID_UNDEFINED_PATTERN_NG, UndefinedPatternNG);
sb.AddAction(SEQ_ID_SET_ALIGN_SEQ_PARAMS, SetAlignSeqParams);
sb.AddSubsequence(SEQ_ID_ALIGN_SEQ, alignSeqBuilder);
sb.AddDecision(SEQ_ID_CHECK_STATUS, CheckStatus);
sb.AddAction(SEQ_ID_MARK_NG, MarkNG);
sb.AddAction(SEQ_ID_DISTANCE_NG, DistanceNG);
sb.AddAction(SEQ_ID_ALIGN_LIMIT_NG, AlignLimitNG);
sb.AddAction(SEQ_ID_RETRY_COUNT_NG, RetryCountNG);
sb.AddAction(SEQ_ID_ALIGN_RESULT_NULL, AlignResultNull);
sb.AddFork(SEQ_ID_FORK);
sb.AddAction(SEQ_ID_APPLY_OFFSET, ApplyOffset);
sb.AddDecision(SEQ_ID_CHECK_MOVE_ENABLED, CheckMoveEnabled);
sb.AddAction(SEQ_ID_MOVE_DELTA, MoveDelta);
sb.AddAction(SEQ_ID_MOVE_FINISHED, MoveFinished);
sb.AddAction(SEQ_ID_UPDATE_UI, UpdateUI);
sb.AddAction(SEQ_ID_SAVE_CSV, SaveCsv);
sb.AddAction(SEQ_ID_SAVE_SCREENSHOT, SaveScreenShot);
sb.AddJoin(SEQ_ID_JOIN);
sb.AddDecision(SEQ_ID_CHECK_RETRY, CheckRetry);
sb.AddAction(SEQ_ID_SEQ_COMPLETE, SeqComplete);
}
public override SequenceBuilder Builder(string seqName) {
_SeqName = seqName;
_TactTimeChecker = new TactTimeChecker(_SeqName);
SequenceBuilder sb = new SequenceBuilder(1000);
SetActions(sb);
sb.OnStopped(OnStopped);
sb.OnForceError(OnForceError);
sb.Flows(
sb.Init
> sb[SEQ_ID_INIT]
> sb[SEQ_ID_CLEAR]
> sb[SEQ_ID_MOVE_FIRST_TEACHING_POS]
> sb[SEQ_CHECK_DRY_RUN]
> sb[SEQ_ID_CHECK_PROC_PATTERN]
> sb[SEQ_ID_SET_ALIGN_SEQ_PARAMS]
> sb[SEQ_ID_ALIGN_SEQ]
> sb[SEQ_ID_CHECK_STATUS]
> sb[SEQ_ID_FORK]
> sb[SEQ_ID_APPLY_OFFSET]
> sb[SEQ_ID_CHECK_MOVE_ENABLED]
> sb[SEQ_ID_MOVE_DELTA]
> sb[SEQ_ID_MOVE_FINISHED]
);
sb.Flows(
sb[SEQ_ID_CHECK_PROC_PATTERN]
> sb[SEQ_ID_UNDEFINED_PATTERN_NG]
> sb[SEQ_ID_SEQ_COMPLETE]
);
sb.Flows(
sb[SEQ_CHECK_DRY_RUN] // Dry Run
> sb[SEQ_ID_SET_DRY_RUN_SEQ_PARAMS]
> sb[SEQ_ID_DRY_RUN_SEQ]
> sb[SEQ_ID_DRY_RUN_UPDATE_UI]
> sb[SEQ_ID_SEQ_COMPLETE]
);
sb.Flows(
sb[SEQ_ID_FORK]
> sb[SEQ_ID_UPDATE_UI]
);
sb.Flows(
sb[SEQ_ID_CHECK_STATUS] // Mark NG
> sb[SEQ_ID_MARK_NG]
> sb[SEQ_ID_SEQ_COMPLETE]
);
sb.Flows(
sb[SEQ_ID_CHECK_STATUS] // Distance NG
> sb[SEQ_ID_DISTANCE_NG]
> sb[SEQ_ID_SEQ_COMPLETE]
);
sb.Flows(
sb[SEQ_ID_CHECK_STATUS] // Align Limit NG
> sb[SEQ_ID_ALIGN_LIMIT_NG]
> sb[SEQ_ID_SEQ_COMPLETE]
);
sb.Flows(
sb[SEQ_ID_CHECK_STATUS] // Retry Count NG
> sb[SEQ_ID_RETRY_COUNT_NG]
> sb[SEQ_ID_SEQ_COMPLETE]
);
sb.Flows(
sb[SEQ_ID_CHECK_STATUS] // Align Result Null
> sb[SEQ_ID_ALIGN_RESULT_NULL]
> sb[SEQ_ID_SEQ_COMPLETE]
);
sb.Flows(
sb[SEQ_ID_CHECK_MOVE_ENABLED]
> sb[SEQ_ID_MOVE_FINISHED]
);
sb.Flows(
sb[SEQ_ID_MOVE_FINISHED]
> sb[SEQ_ID_JOIN]
);
sb.Flows(
sb[SEQ_ID_UPDATE_UI]
> sb[SEQ_ID_SAVE_CSV]
> sb[SEQ_ID_SAVE_SCREENSHOT]
> sb[SEQ_ID_JOIN]
> sb[SEQ_ID_CHECK_RETRY]
> sb[SEQ_ID_SEQ_COMPLETE]
);
sb.Flows(
sb[SEQ_ID_CHECK_RETRY] // Retry
> sb[SEQ_ID_CLEAR]
);
sb.Flows(
sb[SEQ_ID_SEQ_COMPLETE]
> sb.Final
);
#if SEQ_DRAW
sb.Draw($"{GetType().Name}.pdf");
#endif
return sb;
}
private SequenceActionResult Init(
SequenceContext context,
string id,
SequenceActionResult param) {
_TactTimeChecker.Start(TactTimeType.ProcSeq, VisionKeys.AlignProcSeqKey);
if (param.Param != null) {
_Params = param.Param as AlignProcSeqParams;
}
else {
LOG.E($"Param is null.");
return null;
}
_Aligner = AlignAgentManager.GetAlignAgent(_Params.AlignInfo);
_AlignRecipe = VisionRecipeManager.GetAlignRecipe(_Params.AlignInfo);
_SubSysInfo = VisionRecipeManager.GetSubSysInfo(_Params.AlignInfo.UnitId, _Params.AlignInfo.SubSysId);
_VisionLog = new Logger(_SubSysInfo.SubSysName, VisionKeys.LogKey);
_VisionLog.V("[START]");
context.PutValue<ProcParams>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_PROC_PARAMS, _SubSysInfo), _AlignRecipe.ProcParams);
if (_Params.AlignCntClear) {
_Aligner.Clear();
}
if (VisionDBAgentManager.IsUseDB) {
VisionDBAgentManager.GetAlignDBAgent().AllocNextSeqId(_Params.AlignDB);
}
return SequenceAction.Ok();
}
private SequenceActionResult Clear(
SequenceContext context,
string id,
SequenceActionResult param) {
GrabFindSeqUtil.Clear(_SubSysInfo);
AlignResultItemManager.Clear(_SubSysInfo);
PatternResultItemManager.Clear(_SubSysInfo);
return SequenceAction.Ok();
}
private SequenceActionResult MoveFirstTeachingPos(
SequenceContext context,
string id,
SequenceActionResult param) {
if (EquipAdapter.Instance.EquipMode.IsSimulMode()) {
return SequenceAction.Ok();
}
AlignResult alignResult = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
if (_AlignRecipe.ProcParams.FirstTeachingMoveEnabled || // 첫번째 티칭 위치로 이동 설정이 True인 경우 첫 Fov로 이동한다.
(alignResult != null && alignResult.Status == AlignStatus.RETRY && _AlignRecipe.AlignRetry.Enabled)) { // Align Retry 상황의 경우 첫 Fov로 이동한다.
int res = E1.GENERIC;
var fov1Info = new FovInfo(_SubSysInfo, eFovId.Fov1);
if (_Params.FovPositions != null && _Params.FovPositions.ContainsKey(eFovId.Fov1)) {
// 파라미터로 넘겨받은 절대위치로 이동
res = EquipAdapter.Instance.TeachingMotionManager.AbsMove(fov1Info, _Params.FovPositions[eFovId.Fov1]);
}
else {
// Adapter에 정의된 티칭위치로 이동
res = EquipAdapter.Instance.TeachingMotionManager.MovePosition(fov1Info, ePositionType.Teaching);
}
if (res == E1.OK) {
ApplyGrabDelay(_SubSysInfo);
return SequenceAction.Ok();
}
else {
return SequenceAction.Error(E2.ABORTED);
}
}
return SequenceAction.Ok();
}
#region Dry Run
private string CheckDryRun(
SequenceContext context,
string id,
ICollection<string> branches,
SequenceActionResult param) {
if (EquipAdapter.Instance.EquipMode.IsDryrunOrTransferMode()) {
return SEQ_ID_SET_DRY_RUN_SEQ_PARAMS;
}
else {
return SEQ_ID_CHECK_PROC_PATTERN;
}
}
private SequenceActionResult SetDryRunSeqParams(
SequenceContext context,
string id,
SequenceActionResult param) {
var fovInfos = new Dictionary<eFovId, FovInfo>();
foreach (var fovInfo in VisionRecipeManager.GetFovInfos(_SubSysInfo)) {
fovInfos.Add(fovInfo.FovId, fovInfo);
}
return SequenceAction.Ok(new AlignSeqParams_DryRun(_Params.AlignInfo, fovInfos, displayType: _Params.DisplayType));
}
#endregion
private string CheckProcPattern(
SequenceContext context,
string id,
ICollection<string> branches,
SequenceActionResult param) {
var subsysRecipe = VisionRecipeManager.GetSubSysRecipe(_SubSysInfo);
foreach (var fovRecipe in subsysRecipe.FovRecipes) {
if((int)fovRecipe.FovId >= ProcParams.GetFovNum(_AlignRecipe.ProcParams.ProcFovType)) {
// 얼라인에 사용하는 Fov의 수만큼만 확인한다.
continue;
}
foreach (var procPattern in fovRecipe.PatternRecipe.ProcPatternInfos) {
if (_Params.AlignInfo.AlignId.ToString() == procPattern.ProcId) {
if((int)procPattern.ProcPatternId >= ProcParams.GetProcNum(_AlignRecipe.ProcParams.ProcFovType)) {
// 얼라인에 사용하는 Pattern의 수만큼만 확인한다.
continue;
}
if (procPattern.PatternId == -1) {
return SEQ_ID_UNDEFINED_PATTERN_NG;
}
}
}
}
return SEQ_ID_SET_ALIGN_SEQ_PARAMS;
}
private SequenceActionResult UndefinedPatternNG(
SequenceContext context,
string id,
SequenceActionResult param) {
string errMsg = "Undefined PatternID Available";
PrintErrorLogAndShowErrorToast(LOG, errMsg);
context.PutValue<AlignResult>(
string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()),
new AlignResult()
{
Status = AlignStatus.UNDEFINED_PATTERN,
DisplayType = _Params.DisplayType,
AlignAlgorithm = _AlignRecipe.ProcParams.AlignAlgorithm,
});
return SequenceAction.Ok();
}
private SequenceActionResult SetAlignSeqParams(
SequenceContext context,
string id,
SequenceActionResult param) {
return SequenceAction.Ok(new AlignSubSeqParams(_Params.AlignInfo, _Params.FovPositions, _Params.DisplayType, _Params.SeqMode));
}
private string CheckStatus(
SequenceContext context,
string id,
ICollection<string> branches,
SequenceActionResult param) { // Param : AlignResult
var alignResult = param.Param as AlignResult;
alignResult.DisplayType = _Params.DisplayType;
if (alignResult == null) {
return SEQ_ID_ALIGN_RESULT_NULL;
}
if (alignResult.Status == AlignStatus.NOT_FOUND) {
return SEQ_ID_MARK_NG;
}
else if (alignResult.Status == AlignStatus.DISTANCE_NG) {
return SEQ_ID_DISTANCE_NG;
}
else if (alignResult.Status == AlignStatus.ALIGN_LIMIT_OVER) {
return SEQ_ID_ALIGN_LIMIT_NG;
}
else if (alignResult.Status == AlignStatus.RETRY_COUNT_OVER) {
return SEQ_ID_RETRY_COUNT_NG;
}
else {
return SEQ_ID_FORK;
}
}
private SequenceActionResult MarkNG(
SequenceContext context,
string id,
SequenceActionResult param) {
DoNgActions(context, id, param);
return SequenceAction.Error(E1.GENERIC);
}
private SequenceActionResult DistanceNG(
SequenceContext context,
string id,
SequenceActionResult param) {
DoNgActions(context, id, param);
return SequenceAction.Error(E1.GENERIC);
}
private SequenceActionResult AlignLimitNG(
SequenceContext context,
string id,
SequenceActionResult param) {
DoNgActions(context, id, param);
return SequenceAction.Error(E1.GENERIC);
}
private SequenceActionResult RetryCountNG(
SequenceContext context,
string id,
SequenceActionResult param) {
DoNgActions(context, id, param);
return SequenceAction.Error(E1.GENERIC);
}
private SequenceActionResult AlignResultNull(
SequenceContext context,
string id,
SequenceActionResult param) {
return SequenceAction.Ok();
}
private void DoNgActions(
SequenceContext context,
string id,
SequenceActionResult param) {
AlignResult alignResult = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
context.PutValue(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT_WITH_OFFSET, _Params.AlignInfo.GetKey()), alignResult.Clone());
UpdateUI(context, id, param);
SaveCsv(context, id, param);
SaveScreenShot(context, id, param);
}
private SequenceActionResult ApplyOffset(
SequenceContext context,
string id,
SequenceActionResult param) {
AlignResult alignResult = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
AlignResult alignResultWithOffset = alignResult.Clone();
// Retry일 때는 오프셋을 반영하지 않는다.
if (alignResult.Status == AlignStatus.OK || alignResult.Status == AlignStatus.F_OK) {
if (_AlignRecipe.AlignOffset.Enabled) {
var alignOffset = _AlignRecipe.AlignOffset;
alignResultWithOffset.Delta.X += alignOffset.OffsetX;
alignResultWithOffset.Delta.Y += alignOffset.OffsetY;
alignResultWithOffset.Delta.T.Degree += alignOffset.OffsetT;
}
}
context.PutValue(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT_WITH_OFFSET, _Params.AlignInfo.GetKey()), alignResultWithOffset);
return SequenceAction.Ok();
}
private string CheckMoveEnabled(
SequenceContext context,
string id,
ICollection<string> branches,
SequenceActionResult param) {
if (_AlignRecipe.ProcParams.AlignDeltaMoveEnabled && _Params.SeqMode == eSeqMode.Auto) {
return SEQ_ID_MOVE_DELTA;
}
else {
return SEQ_ID_MOVE_FINISHED; // Skip Move
}
}
private SequenceActionResult MoveDelta(
SequenceContext context,
string id,
SequenceActionResult param) {
if (EquipAdapter.Instance.EquipMode.IsSimulMode()) {
return SequenceAction.Ok();
}
AlignResult alignResultWithOffset = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT_WITH_OFFSET, _Params.AlignInfo.GetKey()));
var alignDirector = AlignDirectorManager.Instance.GetDirector(_SubSysInfo);
var motionDelta = alignDirector.ApplyDirection(alignResultWithOffset.Delta.ToPosition());
var res = EquipAdapter.Instance.AlignMotionManager.RelMove(_SubSysInfo, motionDelta);
if (res != E1.OK) {
LOG.E("Move Failed.");
return SequenceAction.Error(E2.ABORTED);
}
return SequenceAction.Ok();
}
private SequenceActionResult MoveFinished(
SequenceContext context,
string id,
SequenceActionResult param) {
// Join을 위해 지나가는 노드
return SequenceAction.Ok();
}
private SequenceActionResult UpdateUI(
SequenceContext context,
string id,
SequenceActionResult param) {
AlignResult alignResult = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
alignResult.DisplayType = _Params.DisplayType; // 개별 AlignSequence 에서 진행해 주어야하는 부분인데, 놓쳤을 시 방어코드개념으로 추가
var subSysInfo = _Params.AlignInfo.ToSubSysInfo();
VisionEnv.AuroraEnv.EventPublisher.Publish(
new EventMessage(_Params.AlignInfo.GetKey(), VisionEventId.UPDATE_ALIGN_RESULT, alignResult));
PrintVisionLog(alignResult);
return SequenceAction.Ok();
}
private SequenceActionResult SaveCsv(
SequenceContext context,
string id,
SequenceActionResult param) {
if (EquipAdapter.Instance.EquipMode.IsNotDryrunAndTransferMode()) {
AlignResult alignResult = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
_CsvManager.SaveCsv(
_Params.AlignInfo, AlignResultItemManager.GetAlignResultItem(_Params.AlignInfo, alignResult), eSaveDataType.Align);
if (VisionDBAgentManager.IsUseDB) {
_Params.AlignDB.AllocAlignResult(alignResult);
_Params.AlignDB.SetSeqEnd();
VisionDBAgentManager.GetAlignDBAgent().SetDataAsync(_Params.AlignDB);
}
}
return SequenceAction.Ok();
}
private SequenceActionResult SaveScreenShot(
SequenceContext context,
string id,
SequenceActionResult param) {
if (EquipAdapter.Instance.EquipMode.IsNotDryrunAndTransferMode()) {
AlignResult alignResult = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
var materialInfo = context.GetValue<MaterialInfo>(VisionContextKeys.CNTXT_KEY_MATERIAL_INFO);
var fovInfo = VisionRecipeManager.GetFovInfo(_SubSysInfo.UnitId, _SubSysInfo.SubSysId, eFovId.Fov1);
if (_Aligner.IsAlignStatusNG(alignResult.Status) || VisionSettingManager.VisionSetting.SaveOkSceenShotImage) {
var lastFovId = context.GetValue<eFovId>(string.Format(VisionContextKeys.CNTXT_KEY_LAST_MEASURE_FOV_ID, _Params.AlignInfo.GetKey()));
_ImageManager.SaveScreenShot(
VisionRecipeManager.GetFovInfo(_SubSysInfo, lastFovId),
alignResult.Status.ToString(), materialInfo, _Params.DisplayType,
AlignResultItemManager.GetTimeStamp(_SubSysInfo, alignResult));
}
}
return SequenceAction.Ok();
}
private string CheckRetry(
SequenceContext context,
string id,
ICollection<string> branches,
SequenceActionResult param) {
AlignResult alignResult = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
if (_Params.SeqMode == eSeqMode.Auto) {
if (_AlignRecipe.AlignRetry.Enabled) {
if (alignResult.Status == AlignStatus.RETRY) {
if (_AlignRecipe.ProcParams.AlignDeltaMoveEnabled) {
return SEQ_ID_CLEAR; // RETRY
}
else {
return SEQ_ID_SEQ_COMPLETE; // RETRY, BUT NOT MOVE
}
}
}
}
return SEQ_ID_SEQ_COMPLETE; // OK
}
private SequenceActionResult SeqComplete(
SequenceContext context,
string id,
SequenceActionResult param) {
AlignResult alignResultWithOffset = new AlignResult();
if (EquipAdapter.Instance.EquipMode.IsNotDryrunAndTransferMode()) {
alignResultWithOffset = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT_WITH_OFFSET, _Params.AlignInfo.GetKey()));
}
else { // DryRun의 경우 Offset이 없는 얼라인 결과를 전달
alignResultWithOffset = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
}
SetPatternResults(context, alignResultWithOffset);
_TactTimeChecker.Stop(TactTimeType.ProcSeq, VisionKeys.AlignProcSeqKey); // 택타임 측정 종료
_VisionLog.V("[END]");
if (context.GetValue<ProcParams>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_PROC_PARAMS, _SubSysInfo)) != null)
{
context.RemoveValue(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_PROC_PARAMS, _SubSysInfo));
}
return SequenceAction.Ok(alignResultWithOffset);
}
private void SetPatternResults(SequenceContext context, AlignResult alignResult) {
var fovInfos = VisionRecipeManager.GetFovInfos(_SubSysInfo);
foreach (FovInfo fovInfo in fovInfos) {
var patternResult = context.GetValue<PatternResult>(string.Format(VisionContextKeys.CNTXT_KEY_PATTERN_RESULT, fovInfo.GetKey()));
if (!alignResult.PatternResults.ContainsKey(fovInfo)) {
alignResult.PatternResults.Add(fovInfo, patternResult);
}
else {
alignResult.PatternResults[fovInfo] = patternResult;
}
}
}
private void PrintVisionLog(AlignResult alignResult) {
_VisionLog.I($"AlignCnt : {alignResult.AlignCnt}");
_VisionLog.I($"dX : {alignResult.Delta.X:F4}, dY : {alignResult.Delta.Y:F4}, dT : {alignResult.Delta.T.Degree:F4}");
_VisionLog.I($"Status : {alignResult.Status}");
_VisionLog.I($"Algorithm : {alignResult.AlignAlgorithm}");
}
void OnStopped(
SequenceContext context) {
LOG.I($"{context.SequenceId} - STOP Handler");
HandleAbnormalFinish(context);
}
void OnForceError(
SequenceContext context, string id) {
LOG.E($"{context.SequenceId} - FORCE ERROR Handler");
HandleAbnormalFinish(context);
}
void HandleAbnormalFinish(
SequenceContext context) {
_TactTimeChecker.Stop(TactTimeType.ProcSeq, VisionKeys.AlignProcSeqKey); // 택타임 측정 종료
if(context.GetValue<ProcParams>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_PROC_PARAMS, _SubSysInfo)) != null)
{
context.RemoveValue(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_PROC_PARAMS, _SubSysInfo));
}
}
}
}