using Aurora.Api; using Aurora.Api.Devices; using Aurora.Api.Services; // 26.04.08 NDY 추가 - 비전 있는 오토 티칭 버튼은 MIL없어서 리스트만으로 테스트 시퀸스 확인하고자 추가 예정 using AuroraACS; using AuroraIO; using AuroraLaserScanner; using AuroraLBAD; using AuroraLBAD.Services; using AuroraMotionBoard.Ajin; using AuroraOCT; using CoreUnit.Control.UserControl.Canvas; using CoreUnit.Scanner.UserControl.ScannerCanvas; using DB; using Hermes; using Matrox.MatroxImagingLibrary; using OpenCvSharp.Dnn; using System; using System.Collections.Generic; using System.Configuration; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using VisionCommon; using WeldingCommon.Alarm; using WeldingCommon.Data; using WeldingCommon.Settings; using WeldingCommon.Utils; using static AuroraIO.AJINEXTEK.AjinIO.IOModuleInfo; using static AuroraIO.Vendor.PAIX.PAIXIO; namespace WeldingCommon.Sequences { public class SeqTeachingRun { static readonly Logger Log = new Logger("SeqTeachingRun"); const string SEQ_ENTER = "[SeqTeachingRun] SEQ_ENTER"; // inputParam 으로 받자. const string SEQ_CHECK_INIT_CONDITION = "[SeqTeachingRun] Check Init Condition"; // Check Init Condition const string SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ = "[SeqTeachingRun] Set Sequence Param (UploadWeldingList Seq)"; const string SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ = "[SeqTeachingRun] Process (UploadWeldingList Seq)"; const string SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ = "[SeqTeachingRun] Get Sequence Result (UploadWeldingList Seq)"; const string SEQ_SET_BLOW_ON = "[SeqTeachingRun] Set Blow On"; const string SEQ_STREAM_LBAD_BEFORE_WELDLINES = "[SeqTeachingRun] StreamLBAD Before Weldlines"; const string SEQ_EXECUTE_WELDLINES = "[SeqTeachingRun] Execute WeldLines"; const string SEQ_SET_BLOW_OFF = "[SeqTeachingRun] Set Blow Off"; const string SEQ_STREAM_LBAD_AFTER_WELDLINES = "[SeqTeachingRun] StreamLBAD After Weldlines"; const string SEQ_SAVE_RESULT_DATA = "[SeqTeachingRun] Save Result Data"; const string SEQ_WRITE_COMPLETION_PLC_BIT = "[SeqTeachingRun] Write Completion PLC Bit"; const string SEQ_COMPLETE = "[SeqTeachingRun] SEQ_COMPLETE"; // 완료 #region 26.04.08 NDY 상수 추가 const string SEQ_MOVE_STAGE_ORIGIN = "[SeqTeachingRun] Move Stage To Origin"; const string SEQ_ENCODER_RESET = "[SeqTeachingRun] Encoder Reset"; #endregion static class ContextKey { public const string KEY_SEQUENCE_RESULT = "KEY_SEQUENCE_RESULT_SeqTeachingRun"; public const string KEY_SEQUENCE_START_TIME = "KEY_SEQUENCE_START_TIME_SeqTeachingRun"; } private SeqTeachingRun_InitParam _InitParam; private Scanner _Scanner; private OCT _OCT; private IODevice _IO; private StreamLBADClient _StreamLBADClient; private ACSMotor _AxisX; // ← 26.04.08 NDY 필드 추가 private SystemParameter _SystemParameter; private ScannerCanvasUserCtrl _ScannerCanvasUserCtrl; //스캐너 동작관련 객체 선언 private eListNo _WeldingScannerListNo; private List _SelectedObjectList; private static TimeSpan _WeldingSpanTime; //TeacingRun 시퀀스에서 용접 소요시간 public SequenceBuilder Builder() { var sb = new SequenceBuilder(1000, true); ////var sb = new SequenceBuilder(1000, false); // With log sb.AddAction(SEQ_ENTER, Sequence_Enter); sb.AddDecision(SEQ_CHECK_INIT_CONDITION, CheckInitCondition); //분기 #region 26.04.08 NDY 노드 추가 sb.AddAction(SEQ_MOVE_STAGE_ORIGIN, MoveStageToOrigin); sb.AddAction(SEQ_ENCODER_RESET, EncoderReset); #endregion sb.AddAction(SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ, SetUploadWeldingList_SeqParams); sb.AddSubsequence(SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ, CommonSequenceManager.GetSeqBuilder_SeqUploadWeldingList()); sb.AddAction(SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ, GetUploadWeldingList_SeqResult); sb.AddAction(SEQ_SET_BLOW_ON, SetBlowOn); sb.AddAction(SEQ_STREAM_LBAD_BEFORE_WELDLINES, StreamLBADBeforeWeldlines); sb.AddAction(SEQ_EXECUTE_WELDLINES, ExecuteWeldLines); sb.AddAction(SEQ_SET_BLOW_OFF, SetBlowOff); sb.AddAction(SEQ_STREAM_LBAD_AFTER_WELDLINES, StreamLBADAfterWeldlines); sb.AddAction(SEQ_SAVE_RESULT_DATA, SaveResultData); // 해당 공정의 정보를 기록 함. sb.AddAction(SEQ_WRITE_COMPLETION_PLC_BIT, WriteCompletionPLCBit); // 정상적으로 종료 되면, complete bit write sb.AddAction(SEQ_COMPLETE, Complete); #region 기존 흐름 26.04.08 주석처리 //sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION] // > sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ] // > sb[SEQ_SET_BLOW_ON] > sb[SEQ_STREAM_LBAD_BEFORE_WELDLINES] > sb[SEQ_EXECUTE_WELDLINES] // > sb[SEQ_SET_BLOW_OFF] > sb[SEQ_STREAM_LBAD_AFTER_WELDLINES] // > sb[SEQ_SAVE_RESULT_DATA] > sb[SEQ_WRITE_COMPLETION_PLC_BIT] > sb[SEQ_COMPLETE]); #endregion #region 2개 노드 추가 흐름 26.04.08 - Test 중 sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_MOVE_STAGE_ORIGIN] // ← 추가 > sb[SEQ_ENCODER_RESET] // ← 추가 > sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_SET_BLOW_ON] > sb[SEQ_STREAM_LBAD_BEFORE_WELDLINES] > sb[SEQ_EXECUTE_WELDLINES] > sb[SEQ_SET_BLOW_OFF] > sb[SEQ_STREAM_LBAD_AFTER_WELDLINES] > sb[SEQ_SAVE_RESULT_DATA] > sb[SEQ_WRITE_COMPLETION_PLC_BIT] > sb[SEQ_COMPLETE]); #endregion sb.Flows(sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_COMPLETE] > sb.Final); sb.OnStopped(OnStopped); sb.OnForceError(OnForceError); //sb.Draw("SeqTeachingRun.pdf"); return sb; } #region 26.04.08 NDY 메서드 추가 private SequenceActionResult EncoderReset(SequenceContext context, string id, SequenceActionResult param) { if (_AxisX == null) { Log.W("[EncoderReset] AxisX2 null - 스킵"); return SequenceAction.Ok(); } if (!_Scanner.Config.UseMarkingOnTheFly) { Log.W("[EncoderReset] MOTF 비활성화 - 스킵"); return SequenceAction.Ok(); } Log.I("[EncoderReset] 시작"); _Scanner.SetFlyX(_Scanner.Config.MarkingOnTheFlyEncoderResolutionX); Log.I($"[EncoderReset] SetFlyX: {_Scanner.Config.MarkingOnTheFlyEncoderResolutionX}"); _Scanner.WaitForEncoderX(_Scanner.Config.MarkingStartEncoderPositionX); Log.I($"[EncoderReset] WaitForEncoderX: {_Scanner.Config.MarkingStartEncoderPositionX}"); _Scanner.StoreEncoder(0); _Scanner.SaveAndRestartTimer(); Log.I("[EncoderReset] 완료 - Stage(0) = Scanner(0) 동기화"); return SequenceAction.Ok(); } private SequenceActionResult MoveStageToOrigin(SequenceContext context, string id, SequenceActionResult param) { if (_AxisX == null) { Log.W("[MoveStageToOrigin] AxisX2 null - 스킵"); return SequenceAction.Ok(); } Log.I("[MoveStageToOrigin] Stage X → 0 이동 시작"); _AxisX.SetTargetPos(0, TargetPosType.ABS); _AxisX.SetMoveVelocityImm(AuroraACS.Speed.M); _AxisX.AccelerationImm(AuroraACS.Speed.M); _AxisX.DecelerationImm(AuroraACS.Speed.M); _AxisX.JerkImm(AuroraACS.Speed.M); _AxisX.Move(); var res = context.RetryUntilSuccess( () => _AxisX.IsReachedTargetPosition(0), 30 * 1000, 20, true); if (res == E2.TIMEOUT) { Log.E("[MoveStageToOrigin] TIMEOUT"); return null; } if (res == E2.CANCELLED) { Log.E("[MoveStageToOrigin] CANCELLED"); return null; } Log.I("[MoveStageToOrigin] Stage X = 0 도달 완료"); return SequenceAction.Ok(); } #endregion private SequenceActionResult Sequence_Enter(SequenceContext context, string id, SequenceActionResult param) { Log.I("SeqTeachingRun Start"); _InitParam = param.Param as SeqTeachingRun_InitParam; _SystemParameter = context.GetSetting(CommonSettingIds.SystemParameter); InitDev(context); if (!CheckDeviceReady(context)) { //Check Device AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_TeachingRun_DeviceNotReady); Log.E("The devices are not active."); return null; } if (InitSequenceVariable(context) == false) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_TeachingRun_InitVariableError); return null; } return SequenceAction.Ok(); } private bool InitSequenceVariable(SequenceContext context) { var mainPage = CommonHelper.GetMainPage(); _ScannerCanvasUserCtrl = mainPage.ScannerCanvasCtrlTeaching; _WeldingScannerListNo = eListNo.LIST1; if (_InitParam.IsObjectSelectAll) { _SelectedObjectList = _ScannerCanvasUserCtrl.Model.ActiveLayer.Objects; } else { _SelectedObjectList = _ScannerCanvasUserCtrl.Canvas.Model.SelectedObjects; } //Status.GetProcessingWeldingData().WeldingScannerListNo = _WeldingScannerListNo; //Status.GetProcessingWeldingData().SelectedDrawObjectList = _SelectedObjectList; return true; } private void InitDev(SequenceContext context) { //Device Init _Scanner = context.GetLaserScanner(); _OCT = context.GetOCT(); _IO = context.GetIOUnit(); if (_InitParam.UseStream) { _StreamLBADClient = context.GetLBADClient(); } // @geprecated 각형배터리에서 문제 생겨서 추가한 코드임 // Scanner를 다시 초기화해주면 시간이 오래걸린다.. 굳이 수동용접시 마다 해줄 필요가 없음 //if (E1.OK != _scanner._scannerObj.Open()) //{ // Log.E("Scanner open Error"); // return SequenceAction.Error(); //} //if (E1.OK != _scanner._scannerObj.Initialize(_scanner.Config)) //{ // Log.E("Scanner Initialize Error"); // return SequenceAction.Error(); //} #region 26.04.08 NDY 수정 예외처리를 위해서 // ↓ 추가 try { _AxisX = context.Devices[CommonDeviceIds.AxisX2] as ACSMotor; } catch { _AxisX = null; Log.W("[SeqTeachingRun] AxisX2 취득 실패"); } #endregion } private bool CheckDeviceReady(SequenceContext context) { List deviceListToCheck = new List() { CommonDeviceIds.Scanner, /*CommonDeviceIds.OCT, */CommonDeviceIds.IODevice }; if (_InitParam.UseStream) { deviceListToCheck.Add(CommonServiceIds.StreamLBADClient); } bool isAllDeviceActivated = true; foreach (string item in deviceListToCheck) { if (!context.Devices[item].IsActivated) { isAllDeviceActivated = isAllDeviceActivated && false; } } return isAllDeviceActivated; } private bool CheckCondition() { if (CheckCondition_Interlock()) { if (InitializeDeviceStatus()) { return true; } } return false; } private bool CheckCondition_Interlock() { // PLC, Data, IO 등 Interlock checking return true; } private bool InitializeDeviceStatus() { //Vision Correction File 선택 //_scanner._scannerObj.SelectCorrectionTable(1); _Scanner.SelectCorrectionTable(2); if (_InitParam.UseStream) { if (InitializeStream() == false) { Log.E("Fail Initialize Stream"); return false; } } return true; } private string CheckInitCondition(SequenceContext context, string id, ICollection branches, SequenceActionResult param) { if (!CheckCondition()) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_TeachingRun_CheckInitCondition); Log.E("Condition is not in state to start sequence."); context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, false); return SEQ_COMPLETE; } var startTime = DateTime.Now; context.PutValue(ContextKey.KEY_SEQUENCE_START_TIME, startTime); Log.D("TeachingRun Sequence CheckInitCondition"); return SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ; } private bool InitializeStream() { // TODO: 이거는 원래 source 에 없었는데, 언제 반영 되었는지 확인 필요. 그리고 맞는 방법으로 되었는지 확인 필요함. // TODO: 우선은 주석 처리 해 둠. 2025.03.05 // TODO: StreamLBADClient 의 생성자에 해당 Message 가 있음. 이걸 좀 바꿔야 함. 생성할때 보내는 것이 맞는지 명시적으로 보내는것이 맞는지. //// CELL ID와 LOT ID는 CellTacker로부터 받은 정보를 LBAD측으로 용접 전 줘야함, Reply는 로그만 남기자 //_StreamLBADClient.AddParser(StreamMessageNames.MESSAGE_PC_LBAD_CELL_ID, new StreamStringParser(), new StreamNumberParser()); //_StreamLBADClient.AddParser(StreamMessageNames.MESSAGE_PC_LBAD_LOT_ID, new StreamStringParser(), new StreamNumberParser()); ////LBAD측이랑 통신하기 전 항상 ReadyStauts에 대한 Request하고 LBAD에서는 Ready가 되있으면 Reply를 한다.. //_StreamLBADClient.AddParser(StreamMessageNames.MESSAGE_PC_LBAD_READY_STATUS, new StreamNumberParser(), new StreamNumberParser()); //_StreamLBADClient.AddParser(StreamMessageNames.MESSAGE_PC_LBAD_WELDING_TRIGGER, new StreamNumberParser(), new StreamNumberParser()); //_StreamLBADClient.AddParser(StreamMessageNames.MESSAGE_PC_LBAD_WELDING_STOP, new StreamNumberParser(), new StreamNumberParser()); ////용접 완료 후 LBAD측에 JudgeComplete를 요청한뒤 JudgeFlag를 회신 받는다 //_StreamLBADClient.AddParser(StreamMessageNames.MESSAGE_PC_LBAD_JUDGEMENT_COMPLETE, new StreamNumberParser(), new StreamNumberParser()); //_StreamLBADClient.AddParser(StreamMessageNames.MESSAGE_PC_LBAD_CELL_ID, new StreamStringParser(), new StreamNumberParser()); //_StreamLBADClient.AddParser(StreamMessageNames.MESSAGE_PC_LBAD_LOT_ID, new StreamStringParser(), new StreamNumberParser()); return true; } private SequenceActionResult SetUploadWeldingList_SeqParams(SequenceContext context, string id, SequenceActionResult param) { // TeachingRun 에서는 CellMeasureCenterOffset 사용하지 않음. 0 으로 넘기자 SeqUploadWeldingList_InitParam seqParams = new SeqUploadWeldingList_InitParam() { NeedSetLaserTiming = _InitParam.NeedSetLaserTiming, IncludeListStartEnd = true, CellMeasureCenterOffsetX = 0.0, CellMeasureCenterOffsetY = 0.0, SelectedDrawObjectList = _SelectedObjectList, WeldingScannerListNo = _WeldingScannerListNo, }; return SequenceAction.Ok(seqParams); } private SequenceActionResult GetUploadWeldingList_SeqResult(SequenceContext context, string id, SequenceActionResult param) { var resultOutParam = param.Param as SeqUploadWeldingList_OutParam; if (resultOutParam.Success == false) { return null; } return SequenceAction.Ok(); } private SequenceActionResult SetBlowOn(SequenceContext context, string id, SequenceActionResult param) { if (_InitParam.UseBlow == false) { return SequenceAction.Ok(); } int intervalTime = _InitParam.IntervalTimeBlowOn; _IO._iOUnit.WriteDoBit(Convert.ToInt32(ePDOAddress.SeamWeldingN2BlowSol), true); _IO._iOUnit.WriteDoBit(Convert.ToInt32(ePDOAddress.SeamWeldingOpticAirKnifeSol), true); Thread.Sleep(intervalTime); Log.D(string.Format($"[TeachingRun] Blow ON Complete")); return SequenceAction.Ok(); } private SequenceActionResult StreamLBADBeforeWeldlines(SequenceContext context, string id, SequenceActionResult param) { if (_InitParam.UseStream == false) { return SequenceAction.Ok(); } if (!_StreamLBADClient.CheckReadyStatus()) { return null; } if (!_StreamLBADClient.SendCellID(1)) { return null; } if (!_StreamLBADClient.SendLotID(2)) { return null; } if (!_StreamLBADClient.SetWeldTriggerOn()) { return null; } return SequenceAction.Ok(); } private SequenceActionResult StreamLBADAfterWeldlines(SequenceContext context, string id, SequenceActionResult param) { if (_InitParam.UseStream == false) { return SequenceAction.Ok(); } //Welding Stop On if (!_StreamLBADClient.SendWeldingStop()) { return null; } //JudgeFlag에 따라서 시퀀스 결정 var judgeFlag = _StreamLBADClient.CheckJudgeComplete(); if (judgeFlag == StreamLBADClient.eJudgeFlag.NO_RESPONSE) { return null; } return SequenceAction.Ok(); } private SequenceActionResult ExecuteWeldLines(SequenceContext context, string id, SequenceActionResult param) { Log.D(string.Format($"[TeachingRun] Welding Start")); DateTime weldingTime = DateTime.Now; _Scanner.ExecuteList(_WeldingScannerListNo); _Scanner.WaitForListTaskCompleted(_SystemParameter.WeldLinesTaskTimeOut); _WeldingSpanTime = DateTime.Now.Subtract(weldingTime); Log.D(string.Format($"[TeachingRun] Welding Complete Time : {_WeldingSpanTime.TotalMilliseconds}")); double dExecuteListTime = _Scanner.GetTime(); Log.I(string.Format($"[TeachingRun] ExecuteList Time : {dExecuteListTime * 1000} msec")); //Welding Stop On if (_InitParam.UseStream) { if (!_StreamLBADClient.SendWeldingStop()) { return null; } } // OCT File Fomrat Record Test //SaveOCTFileFormat(); // File Format Record Test weldingTime = DateTime.Now; //SaveScannerRecordFileForamt(); _WeldingSpanTime = DateTime.Now.Subtract(weldingTime); Log.D(string.Format($"[TeachingRun] SaveScannerRecordFileForamt Time : {_WeldingSpanTime.TotalMilliseconds}")); weldingTime = DateTime.Now; _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); //용접 완료 후 CorrectionFile Vision으로 원복 _Scanner.SelectCorrectionTable(1); _WeldingSpanTime = DateTime.Now.Subtract(weldingTime); Log.D(string.Format($"[TeachingRun] Change SelectCorrectionTable Time : {_WeldingSpanTime.TotalMilliseconds}")); return SequenceAction.Ok(); } private void SaveScannerRecordFileForamt() { _Scanner.SaveRecord("Normal"); } private void SaveOCTFileFormat() { // TODO: ian0513.kim, DataPath 옮겨야 함. var DefaultPath = ConfigurationManager.AppSettings.Get("DATA_PATH"); string fullPath = Path.Combine(DefaultPath, "_device", "_scanner", "Record"); string coordinateFolderpath = fullPath + string.Format("\\Coordinate"); string metaDataFolderpath = fullPath + string.Format("\\Metadata"); if (Directory.Exists(coordinateFolderpath) == false) { Directory.CreateDirectory(coordinateFolderpath); } if (Directory.Exists(metaDataFolderpath) == false) { Directory.CreateDirectory(metaDataFolderpath); } List MetaDataWeldName = new List(_SelectedObjectList.Count); List MetaDataWeldType = new List(_SelectedObjectList.Count); List MetaDataWeldCoordinateID = new List(_SelectedObjectList.Count); int iCoordinateID = 0; for (int i = 0; i < _SelectedObjectList.Count; i++) { if (_SelectedObjectList.ElementAt(i).Type == "Dot") { MetaDataWeldCoordinateID.Add(0); } else { MetaDataWeldCoordinateID.Add(++iCoordinateID); } MetaDataWeldName.Add(_SelectedObjectList.ElementAt(i).Type + (i + 1)); MetaDataWeldType.Add(_SelectedObjectList.ElementAt(i).Type); //MetaDataWeldCoordinateID.Add(m_selectedObjects.ElementAt(i).No + 1) } _Scanner.SaveRecord("CoordinateFile", true, MetaDataWeldCoordinateID, iCoordinateID); _OCT.SaveMetaData(MetaDataWeldName, MetaDataWeldType, MetaDataWeldCoordinateID); string coordinateFilepath = _Scanner.GetLatestFile(coordinateFolderpath); string metaDataFilepath = _Scanner.GetLatestFile(metaDataFolderpath); _Scanner.SaveRecordZip(coordinateFilepath, metaDataFilepath); MetaDataWeldName.Clear(); MetaDataWeldType.Clear(); MetaDataWeldCoordinateID.Clear(); } private SequenceActionResult SetBlowOff(SequenceContext context, string id, SequenceActionResult param) { if (_InitParam.UseBlow == false) { return SequenceAction.Ok(); } int intervalTime = _InitParam.IntervalTimeBlowOff; Thread.Sleep(intervalTime); _IO._iOUnit.WriteDoBit(Convert.ToInt32(ePDOAddress.SeamWeldingN2BlowSol), false); _IO._iOUnit.WriteDoBit(Convert.ToInt32(ePDOAddress.SeamWeldingOpticAirKnifeSol), false); Log.D(string.Format($"[TeachingRun] Blow OFF Complete")); return SequenceAction.Ok(); } private SequenceActionResult SaveResultData(SequenceContext context, string id, SequenceActionResult param) { // 결과 Data 를 업데이트 함. context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, true); return SequenceAction.Ok(); } private SequenceActionResult WriteCompletionPLCBit(SequenceContext context, string id, SequenceActionResult param) { // 완료 비트 write 하는 Node 추가 필요. format 유지, SeqScoutNormal 없음 Log.D("TeachingRun Sequence WriteCompletionPLCBit"); return SequenceAction.Ok(); } private SequenceActionResult Complete(SequenceContext context, string id, SequenceActionResult param) { RestoreDeviceStatus(); Log.I("TeachingRun Complete"); context.TryGetValue(ContextKey.KEY_SEQUENCE_RESULT, out bool seqResult); SeqTeachingRun_OutParam result = new SeqTeachingRun_OutParam() { Success = seqResult }; if (seqResult == false) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_TeachingRun_ResultFailed); } Log.D("TeachingRun Sequence Complete"); return SequenceAction.Ok(result); } private bool RestoreDeviceStatus() { return true; } private void OnForceError(SequenceContext arg1, string arg2) { //List 실행 종료 _Scanner.StopExecution(); //Anlog 출력 0으로 변경, efunctiontype을 command로 변경해주면 list가 아니라 직접 변경됨 _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.COMMAND); //Scanner 원점 복귀 _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); Log.I("SequenceAction Ok : OnForceError"); } private void OnStopped(SequenceContext obj) { //List 실행 종료 _Scanner.StopExecution(); //Anlog 출력 0으로 변경, efunctiontype을 command로 변경해주면 list가 아니라 직접 변경됨 _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.COMMAND); //Scanner 원점 복귀 _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); Log.I("SequenceAction Ok : OnStopped"); } } // TODO: UseStream 으로 TeachingRun 을 할 필요가 있을까?? 확인 필요 public class SeqTeachingRun_InitParam : InitParam { public bool IsUseExternalObjects { get; set; } public List ExternalObjects { get; set; } public bool IsObjectSelectAll { get; set; } // All == true, Selected Object == false public bool UseStream { get; set; } public bool UseBlow { get; set; } public int IntervalTimeBlowOn { get; set; } public int IntervalTimeBlowOff { get; set; } public bool NeedSetLaserTiming { get; set; } // For SubSequence, SeqUploadWeldingList public double CellCenterOffsetX { get; set; } = 0; public double CellCenterOffsetY { get; set; } = 0; } public class SeqTeachingRun_OutParam : OutParam { } }