/* * Copyright (c) 2025 LG Electronics Inc. * SPDX-License-Identifier: LicenseRef-LGE-Proprietary */ using Aurora.Api; using VisionLight; using VisionCommon; using Hermes; using System; using System.Collections.Generic; using System.Reactive.Linq; using VisionSequence.Pattern; using Aurora.View; namespace VisionSequence.Camera { /// /// 카메라 그랩 시퀀스 파라미터 /// public class GrabSeqParams : GrabFindProcSeqParams { /// /// 그랩 시퀀스 파라미터 생성자 /// /// FOV 키 정보 /// 패턴 정보 /// 메인 화면 타입 /// 매뉴얼 시퀀스 플래그 public GrabSeqParams( FovInfo fovInfo, PatternInfo patternInfo, eDisplayType displayType = eDisplayType.Main_1, eSeqMode seqMode = eSeqMode.Auto) : base(fovInfo, patternInfo, displayType, seqMode) { } } /// /// 카메라 그랩 시퀀스 /// public class GrabSeq : SubSeqBase, IDisposable { private readonly Logger LOG = new Logger("GrabSeq"); private GrabSeqParams _Params; private FovRecipe _FovRecipe; private CamConfig _CamConfig; private CameraAgentBase _CameraAgent; private ICameraDisplay _CameraDisplay; private object _GrabImage = null; #region Sequence Id private const string SEQ_ID_INIT = "INIT"; private const string SEQ_ID_CHECK_GRAB_DONE = "CHECK_GRAB_DONE"; private const string SEQ_ID_LIGHT = "LIGHT"; private const string SEQ_ID_LIGHT_NG = "LIGHT_NG"; private const string SEQ_ID_GRAB = "GRAB"; private const string SEQ_ID_GRAB_NG = "GRAB_NG"; private const string SEQ_ID_SET_IMAGE_IN_OTHER_DISPLAY = "SET_IMAGE_IN_OTHER_DISPLAY"; private const string SEQ_ID_SEQ_COMPLETE = "SEQ_COMPLETE"; #endregion /// /// 생성자 /// public GrabSeq() { } private void SetActions(SequenceBuilder sb) { sb.AddAction(SEQ_ID_INIT, Init); sb.AddDecision(SEQ_ID_CHECK_GRAB_DONE, CheckGrabDone); sb.AddDecision(SEQ_ID_LIGHT, SetLight); sb.AddAction(SEQ_ID_LIGHT_NG, LightNG); sb.AddDecision(SEQ_ID_GRAB, Grab); sb.AddAction(SEQ_ID_GRAB_NG, GrabNG); sb.AddAction(SEQ_ID_SET_IMAGE_IN_OTHER_DISPLAY, SetImageInOtherDisplay); sb.AddAction(SEQ_ID_SEQ_COMPLETE, SeqComplete); } public override SequenceBuilder Builder(string 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_CHECK_GRAB_DONE] > sb[SEQ_ID_LIGHT] > sb[SEQ_ID_GRAB] > sb[SEQ_ID_SET_IMAGE_IN_OTHER_DISPLAY] > sb[SEQ_ID_SEQ_COMPLETE] > sb.Final ); sb.Flows( sb[SEQ_ID_LIGHT] > sb[SEQ_ID_LIGHT_NG] > sb.ForceError ); sb.Flows( sb[SEQ_ID_GRAB] > sb[SEQ_ID_GRAB_NG] > sb.ForceError ); sb.Flows( sb[SEQ_ID_CHECK_GRAB_DONE] > sb[SEQ_ID_SEQ_COMPLETE] ); #if SEQ_DRAW sb.Draw($"{GetType().Name}.pdf"); #endif return sb; } private SequenceActionResult Init( SequenceContext context, string id, SequenceActionResult param) { if (param.Param != null) { _Params = param.Param as GrabSeqParams; } else { LOG.E($"_Params is null."); return null; } _FovRecipe = VisionRecipeManager.GetFovRecipe(_Params.FovInfo); _CameraDisplay = CameraDisplayManager.GetDisplay(_Params.FovInfo, _Params.DisplayType); SetCameraAgent(); SetCamConfig(); return SequenceAction.Ok(); } private void SetCameraAgent() { _CameraAgent = CameraAgentManager.GetCameraAgent(_Params.FovInfo); } private void SetCamConfig() { var camRecipe = VisionRecipeManager.GetCamRecipe(_Params.FovInfo); _CamConfig = VisionEnv.AuroraEnv.DeviceManager.GetDeviceConfig(camRecipe.CamId.ToString()) as CamConfig; } // 사용하는 곳에서 그랩 버퍼 할당, 디바이스에서는 복사본 전달 private void InitGrabImageBuffer() { _GrabImage = GrabFindSeqUtil.GetProcGrabImage(_Params.FovInfo, _Params.PatternInfo.LightInfo); } private string CheckGrabDone( SequenceContext context, string id, ICollection branches, SequenceActionResult param) { // IsGrabDone 체크 후, GetGrabImage를 수행해야 한다. var isGrabDone = GrabFindSeqUtil.IsProcGrabDone(_Params.FovInfo, _Params.PatternInfo.LightInfo); InitGrabImageBuffer(); if (_Params.SeqMode == eSeqMode.Manual || !isGrabDone) { return SEQ_ID_LIGHT; } _GrabImage = GrabFindSeqUtil.GetProcGrabImage(_Params.FovInfo, _Params.PatternInfo.LightInfo); SetGrabImage(context, _GrabImage); return SEQ_ID_SEQ_COMPLETE; } #region Set Params private string SetLight( SequenceContext context, string id, ICollection branches, SequenceActionResult param) { int chCnt = _Params.PatternInfo.LightInfo.LightParams.Count; if (chCnt == 0) { string errMsg = "The count of PatternInfo.LightInfo.LightParams is zero."; PrintErrorLogAndShowErrorToast(LOG, errMsg); return SEQ_ID_LIGHT_NG; } eLightResult res = LightHub.Instance.SetLevels(_Params.PatternInfo.LightInfo.LightParams); if (res == eLightResult.NG) { string errMsg = "Failed to set light levels."; PrintErrorLogAndShowErrorToast(LOG, errMsg); return SEQ_ID_LIGHT_NG; } return SEQ_ID_GRAB; } private SequenceActionResult LightNG( SequenceContext context, string id, SequenceActionResult param) { LOG.FuncE("Light NG!!"); EquipAdapter.Instance.VisionAlarm.SetAlarm(eVisionAlarmCode.LIGHT_SET_ERROR); return SequenceAction.Error(E1.GENERIC, null); } private string Grab( SequenceContext context, string id, ICollection branches, SequenceActionResult param) { _CameraDisplay.SetVisibility(); if (_GrabImage == null) { return SEQ_ID_GRAB_NG; } int result = E1.GENERIC; bool isProcExtTrig = false; // 공정 중 외부 트리거 여부 if (_Params.SeqMode == eSeqMode.VisionImageTest) { var visionImageTester = VisionImageTesterManagerBase.GetVisionImageTester(_Params.FovInfo); result = visionImageTester.GetCurrentImage(_CameraDisplay, ref _GrabImage); } else { if (_Params.SeqMode == eSeqMode.Auto) { if (_CamConfig.TriggerMode.IsExternal) { isProcExtTrig = true; } } if (isProcExtTrig) { result = _CameraAgent.GetGrabImageFromBuffer(_CameraDisplay, ref _GrabImage); // 공정 중 외부(버퍼)에서 트리거 발생 var camDev = _CameraAgent.GetDevice(); camDev.SetHookCompletedByExtTrig(false); } else { result = _CameraAgent.GrabSync(_CameraDisplay, ref _GrabImage); // 그 외 경우 Aurora에서 트리거 발생 } } if (result != E1.OK) { SetGrabImage(context, null); return SEQ_ID_GRAB_NG; } else { SetGrabImage(context, _GrabImage); return SEQ_ID_SET_IMAGE_IN_OTHER_DISPLAY; } } private void SetGrabImage(SequenceContext context, object grabImage) { GrabFindSeqUtil.SetProcGrabImage(_Params.FovInfo, _Params.PatternInfo.LightInfo, grabImage); context.PutValue(string.Format(VisionContextKeys.CNTXT_KEY_GRAB_IMAGE, _Params.FovInfo.GetKey()), grabImage); } private SequenceActionResult GrabNG( SequenceContext context, string id, SequenceActionResult param) { LOG.FuncE("Grab NG!!"); EquipAdapter.Instance.VisionAlarm.SetAlarm(eVisionAlarmCode.CAMERA_GRAB_ERROR); return SequenceAction.Error(E1.GENERIC, null); } /// /// 같은 카메라에 대한 다른 메인 디스플레이 군에도 이미지를 Set해준다. /// private SequenceActionResult SetImageInOtherDisplay( SequenceContext context, string id, SequenceActionResult param) { int result = E1.GENERIC; if (_GrabImage != null && CamCommon.IsMainType(_Params.DisplayType)) { foreach (var mainUiRecipe in _FovRecipe.MainUiRecipes) { if (mainUiRecipe.MainDisplayType != _Params.DisplayType && mainUiRecipe.FovUiPos != eFovUiPos.None) { var cameraDisplay = CameraDisplayManager.GetDisplay(_Params.FovInfo, mainUiRecipe.MainDisplayType); result = cameraDisplay.SetImage(_GrabImage); if (!result.Equals(E1.OK)) { return SequenceAction.Error(); } } } } return SequenceAction.Ok(); } #endregion private SequenceActionResult SeqComplete( SequenceContext context, string id, SequenceActionResult param) { var grabImage = context.GetValue(string.Format(VisionContextKeys.CNTXT_KEY_GRAB_IMAGE, _Params.FovInfo.GetKey())); if (grabImage == null) { LOG.FuncE($"[{_Params.FovInfo.SubSysName}][{_FovRecipe.FovName}] grabImage is null."); return SequenceAction.Error(E1.ARGUMENT, grabImage); } return SequenceAction.Ok(grabImage); } 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) { } /// /// 이미지 버퍼 명시적 메모리 해제 /// public void Dispose() { IpAdapter.Instance.IpEnvironment.FreeImage(_GrabImage); } } }