using Aurora; using Aurora.Api; using Aurora.Api.Manager; using Aurora.View; using AuroraLaserScanner; using CoreUnit.Scanner.UserControl.ScannerCanvas; using ILSOS_PrismaticScanner.Device; using ILSOS_PrismaticScanner.Recipes; using ILSOS_PrismaticScanner.Sequences; using System; using System.Collections.Generic; using System.Linq; using System.Reactive.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Threading; using VisionCommon; using WeldingCommon; using WeldingCommon.Alarm; using WeldingCommon.Data; using WeldingCommon.Devices; using WeldingCommon.Popup; using WeldingCommon.Sequences; using WeldingCommon.Sequences.Main; using WeldingCommon.Settings; using WeldingCommon.Utils; using WeldingCommon.Views; using static ILSOS_PrismaticScanner.Device.PLCControllerPrismaticScanner; using static WeldingCommon.Sequences.Main.SeqExecutePlcBitInterface_InitParam; using static WeldingCommon.Views.UCCommonAutoRunViewModel; namespace ILSOS_PrismaticScanner.Views { public class UCMainAutoRunViewModel : UCCommonAutoRunViewModel { private readonly Logger Log = new Logger("UCMainAutoRunViewModel"); public ICommand CMD_VisibleChanged { get; } public ICommand CMD_RunSequenceAutoRun { get; } public ICommand CMD_StopSequenceAutoRun { get; } public ICommand CMD_Reset { get; } // Totoal Product, Today Product #region 26.04.10 NDY - MOTF AutoRun Command public ICommand CMD_StartMOTF { get; } public ICommand CMD_StopMOTF { get; } #endregion private readonly IRecipeManager _RecipeManager; private readonly ISettingEntry _SettingEntry; private readonly IAlarmService _AlarmService; private SystemParameter _SystemParameter; private readonly Scanner _Scanner; private readonly PLCControllerPrismaticScanner _Plc; private ISequence _SeqAutoRun; private ISequence _SeqPlcInterface; private ISequence _SeqQTest; #region 26.04.10 NDY - MOTF AutoRun Sequence // 기존 _SeqAutoRun과 별개로 MOTF 전용 시퀀스 참조 private ISequence _SeqMOTF; #endregion public bool IsSequenceRunning_AutoRun { get => _IsSequenceRunning_AutoRun; set => SetProperty(ref _IsSequenceRunning_AutoRun, value); } private bool _IsSequenceRunning_AutoRun; public bool IsAlarm { get => _IsAlarm; set => SetProperty(ref _IsAlarm, value); } private bool _IsAlarm; private DateTime _NowDateTime; public DateTime NowDateTime { get => _NowDateTime; set => SetProperty(ref _NowDateTime, value); } public WeldingData CurrentWeldingData { get => Status.GetProcessingWeldingData(); } private readonly DispatcherTimer _MonitorTimer; public UCMainAutoRunViewModel(IAuroraEnvironment aurora, string sequenceId) : base(aurora, sequenceId) { _RecipeManager = _Aurora.RecipeManager; _SettingEntry = _Aurora.SettingEntry; _AlarmService = _Aurora.AlarmService; _SystemParameter = _Aurora.SettingEntry[CommonSettingIds.SystemParameter] as SystemParameter; _Scanner = _Aurora.DeviceManager[CommonDeviceIds.Scanner] as Scanner; _Plc = _Aurora.DeviceManager[CommonDeviceIds.PLCDevice] as PLCControllerPrismaticScanner; // MainViewModel에서 RunStateChanged를 설정해준다면, ManualView 상태에서도 해당 이벤트가 호출될지.. 호출될 듯 하긴 함. _SeqAutoRun = _Aurora.SequenceEntry[SequenceIds.SeqAutoRun]; // Autorun과 Status 변경(Manual, Auto 변경) 시 사용하는 시퀸스ID가 다르도록 설정. 같을 경우, 문제 발생. _SeqPlcInterface = _Aurora.SequenceEntry[SequenceIds.SeqExecutePlcBitInterfaceForStatusChange]; // Q Test _SeqQTest = _Aurora.SequenceEntry[SequenceIds.SeqEventQTest]; #region 26.04.10 NDY - MOTF AutoRun Sequence 참조 // 기존 SeqAutoRun과 별개로 MOTF 전용 시퀀스 ID로 참조 _SeqMOTF = _Aurora.SequenceEntry[SequenceIds.SeqAutoRunACS]; #endregion InitVariable(); CMD_VisibleChanged = new DelegateCommand(VisibleChanged); CMD_RunSequenceAutoRun = new DelegateCommand(OnAutoRunStartRequest); CMD_StopSequenceAutoRun = new DelegateCommand(OnStopSequenceAutoRun); CMD_Reset = new DelegateCommand(PerformCmdReset); #region 26.04.10 NDY - MOTF AutoRun Command 등록 // 기존 CMD_RunSequenceAutoRun / CMD_StopSequenceAutoRun 패턴과 동일 CMD_StartMOTF = new DelegateCommand(OnMOTFStartRequest); CMD_StopMOTF = new DelegateCommand(OnStopMOTF); #endregion _MonitorTimer = new DispatcherTimer(); _MonitorTimer.Tick += OnMonitoring; _MonitorTimer.Interval = TimeSpan.FromMilliseconds(100); _Aurora.EventObservable.AsObservable(CommonEventIds.EVENT_AUTO_RUN_START_REQUEST) .ObserveOnDispatcher() .Subscribe(x => OnAutoRunStartRequest()); // Stop이 내려와도 실제 Stop하지 않도록 함 _Aurora.EventObservable.AsObservable(CommonEventIds.EVENT_AUTO_RUN_STOP_REQUEST) .ObserveOnDispatcher() .Subscribe(x => new object()); _Aurora.EventObservable.AsObservable(CommonEventIds.EVENT_EQUIPMENT_STATUS_CHANGE) .Subscribe(x => IsSequenceRunning_AutoRun = Status.EquipmentStatus == eEqpStatus.Auto); Observable.Merge( _Aurora.EventObservable.AsObservable(AuroraSysEvent.SYS_ALARM_SET_ALARM), _Aurora.EventObservable.AsObservable(AuroraSysEvent.SYS_ALARM_RESET_ALARM), _Aurora.EventObservable.AsObservable(AuroraSysEvent.SYS_ALARM_RESET_ALL_ALARM)) .Subscribe(x => IsAlarm = AlarmManager.HasAlarmLevelHigh()); _Aurora.EventObservable.AsObservable(CommonEventIds.EVENT_CHANGE_RECIPE_INFO) .ObserveOnDispatcher() .Select(param => (RecipeInfo)param.Param) .Subscribe(OnUpdateCurrentActivatedRecipe); Status.SetWorkingPosition(eWorkingPosition.NONE); } private void InitVariable() { NowDateTime = DateTime.Now; if (NowDateTime.Day != _SystemParameter.LastProductTime.Day) InitializeTodayCount(); CurrentWeldingData.TodayProduct = _SystemParameter.TodayProductCount; CurrentWeldingData.TotalProduct = _SystemParameter.TotalProductCount; CurrentWeldingData.AutoRunStartTime = default(DateTime); CurrentWeldingData.WeldingEndTime = _SystemParameter.LastProductTime; CurrentWeldingData.WeldingSpanTimeMilliseconds = "0"; CurrentWeldingData.LotId = "Default_Lot_Id"; CurrentWeldingData.CellId = "Default_Cell_Id"; } private void OnUpdateCurrentActivatedRecipe(RecipeInfo info) { // Activate Layer 불러오기 RecipeHelper.OnActiveReloaded(); // Page UI 업데이트 RecipeHelper.UpdateAutorunRecipe(); } private void VisibleChanged(object obj) { bool visible = (bool)obj; if (visible) { _MonitorTimer.Start(); } else { _MonitorTimer.Stop(); } } private void OnMonitoring(object sender, EventArgs e) { // 켜져있는 상태에서는 24시 넘어갈 때만 초기화 if (NowDateTime.Day != DateTime.Now.Day) InitializeTodayCount(); NowDateTime = DateTime.Now; } // PLC 비트에 의한 AutoRun 실행의 경우, PLC 인터페이스 이후 AutoRun 필요 public override async void OnAutoRunStartRequest(object obj = null) { if (!ApproveAutorunByUserOrAuto()) { return; } base.OnAutoRunStartRequest(); //// PLC_AUTO_REQ 신호가 점멸로 오기 때문에.. 일단 auto로 살림 //_Plc.WriteBit(eBitOutput.PC_AUTO_STATUS, true); bool IsStart = await TimerMessageBox.ShowAsync(Application.Current.MainWindow, "운전 시작", "자동 운전을 시작하시겠습니까?", true, 5000); if (!IsStart) { return; } // PLC에선 Auto Req 받으면 바로 살려주도록 Status.GetProcessingWeldingData().AutoRunStartTime = DateTime.Now; RunSequenceAutoRun(); } private void RunSequenceAutoRun() { // 자동으로 Activated Recipe로 변경 OnUpdateCurrentActivatedRecipe(null); var param = new SeqAutoRunPrismaticScanner_InitParam() { //VisionRecipeNo = 0 // 해당 InitParam에는 없는 선언 }; Status.SetStatus(eEqpStatus.Auto); _SeqAutoRun.Start(param, OnCompleteAutoRun); } private void OnCompleteAutoRun(SequenceActionResult res) { if (res != null) { if (res.Param is SeqAutoRunPrismaticScanner_OutParam result && result.Success == true) { MessageUtil.ShowSuccessToast(string.Format("Success SeqAutoRunPrismaticScanner")); return; } } MessageUtil.ShowWarningToast(string.Format("Fail SeqAutoRunPrismaticScanner")); } private bool ApproveAutorunByUserOrAuto() { bool boolian = AlarmManager.HasAlarmLevelHigh(); if (boolian) { Log.E($"Clear Heavy Alarms For Welding!"); MessageUtil.ShowWarningToast(string.Format("Clear Heavy Alarms For Welding!")); return false; } boolian = AlarmManager.IsPlcDoorOpen(); if (boolian) { Log.E($"PLC Door Opened!! Can't Weld Now."); MessageUtil.ShowWarningToast(string.Format("Close Door ! Clear PLC DoorInterlock!")); return false; } boolian = AlarmManager.IsPlcEmoAlarm(); if (boolian) { Log.E($"PLC EMO Pushed!! Can't Weld Now."); MessageUtil.ShowWarningToast(string.Format("Clear PLC EMO Status!")); return false; } if (VisionRecipeManager.GetFovInfos().Count == 0) { MessageUtil.ShowWarningToast(string.Format("Please check the Vision Recipe of the currently active Recipe.")); return false; } if (_SeqAutoRun.RunState == SequenceRunState.Running) { MessageUtil.ShowWarningToast(string.Format("이미 시퀀스가 Start 상태입니다.", "SeqAutoRunPrismaticScanner"), Log); return false; } return true; } public override void OnAutoRunStopRequest() { base.OnAutoRunStopRequest(); //// Prewelding은 자동 운전 정지 와도 무시 //StopSequenceAutoRun(); } private void OnStopSequenceAutoRun(object obj = null) { if (_SeqAutoRun.RunState == SequenceRunState.Idle) { return; } _SeqAutoRun.Stop(); //Recipe를 기존에 선택된 Recipe로 Rollback 해 줌 RecipeHelper.RollbackRecipe(); //AutoRun 정지 시 CorrectionFile을 Vision으로 변경 _Scanner.SelectCorrectionTable(1); } #region 26.04.10 NDY - MOTF AutoRun 실행 / 정지 // 기존 OnAutoRunStartRequest / OnStopSequenceAutoRun 패턴과 동일 // 테스트 버튼용이므로 TimerMessageBox 확인 다이얼로그는 생략 private void OnMOTFStartRequest(object obj = null) { // 기존 AutoRun 인터락 조건 동일하게 적용 if (_SeqMOTF.RunState == SequenceRunState.Running) { MessageUtil.ShowWarningToast("이미 MOTF 시퀀스가 Start 상태입니다.", Log); return; } // 자동으로 Activated Recipe로 변경 OnUpdateCurrentActivatedRecipe(null); Status.GetProcessingWeldingData().AutoRunStartTime = DateTime.Now; Status.SetStatus(eEqpStatus.Auto); var param = new SeqAutoRunPrismaticScannerACS_InitParam(); _SeqMOTF.Start(param, OnCompleteMOTF); Log.I("MOTF Sequence Started"); } private void OnCompleteMOTF(SequenceActionResult res) { // 기존 OnCompleteAutoRun 패턴과 동일 if (res != null) { if (res.Param is SeqAutoRunPrismaticScannerACS_OutParam result && result.Success == true) { MessageUtil.ShowSuccessToast("Success MOTF Sequence"); return; } } MessageUtil.ShowWarningToast("Fail MOTF Sequence"); } private void OnStopMOTF(object obj = null) { // 기존 OnStopSequenceAutoRun 패턴과 동일 if (_SeqMOTF.RunState == SequenceRunState.Idle) { return; } _SeqMOTF.Stop(); Log.I("MOTF Sequence Stopped"); } #endregion private void PerformCmdReset(object commandParameter) { // SystemParameter를 저장하기 전에는 반드시 업데이트를 해주어야 한다. _SystemParameter = _Aurora.SettingEntry[CommonSettingIds.SystemParameter] as SystemParameter; switch ((string)commandParameter) { case "TotalProduct": { CurrentWeldingData.TotalProduct = 0; _SystemParameter.TotalProductCount = CurrentWeldingData.TotalProduct; Status.GetProcessingWeldingData().TotalProduct = 0; _SettingEntry.Save(CommonSettingIds.SystemParameter, _SystemParameter, "UCMainAutoRunViewModel"); } break; case "TodayProduct": { CurrentWeldingData.TodayProduct = 0; _SystemParameter.TodayProductCount = CurrentWeldingData.TodayProduct; Status.GetProcessingWeldingData().TodayProduct = 0; _SettingEntry.Save(CommonSettingIds.SystemParameter, _SystemParameter, "UCMainAutoRunViewModel"); } break; default: return; } } private void InitializeTodayCount() { // SystemParameter를 저장하기 전에는 반드시 업데이트를 해주어야 한다. // SystemParameter에 저장된 값 불러오기 _SystemParameter = _Aurora.SettingEntry[CommonSettingIds.SystemParameter] as SystemParameter; CurrentWeldingData.TodayProduct = 0; _SystemParameter.TodayProductCount = CurrentWeldingData.TodayProduct; _SettingEntry.Save(CommonSettingIds.SystemParameter, _SystemParameter, "UCMainAutoRunViewModel"); } } enum InputType { keyboardInput, ClickInput } }