using Aurora; using Aurora.Api; using Aurora.Api.Manager; using Aurora.Framework.Core; using Aurora.View; using CoreUnit.Control.UserControl.Canvas; using CoreUnit.Scanner.UserControl.ScannerCanvas; using DB.Recipe; using GUI; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reactive.Linq; using System.Text; using System.Threading.Tasks; using VisionCommon; using WeldingCommon.Alarm; using WeldingCommon.Devices; using WeldingCommon.Recipes; using WeldingCommon.Settings; using WeldingCommon.Utils; using WeldingCommon.Utils.Diff; namespace WeldingCommon.Views { public class UCScannerObjectTeachingViewModel : NotifyPropertyChangedBase, IRecipeViewModel { private readonly Logger Log = new Logger("UCScannerObjectTeachingViewModel"); private readonly IAuroraEnvironment _Aurora; private readonly IRecipeManager _RecipeManager; private readonly IModelManager _ModelManager; private PLCController _PLC; private ScannerCanvasUserCtrl _ScannerCanvasUserCtrl; public bool IsManualStatus { get => _IsManualStatus; set => SetProperty(ref _IsManualStatus, value); } private bool _IsManualStatus = true; public UCScannerObjectTeachingControlBoxViewModel ScannerObjectTeachingControlBoxViewModel { get; } private RecipeWeldingLines _RecipeBeforeChanged; public UCScannerObjectTeachingViewModel(IAuroraEnvironment aurora) { _Aurora = aurora; _RecipeManager = aurora.RecipeManager; _ModelManager = aurora.ModelManager; _PLC = aurora.DeviceManager[CommonDeviceIds.PLCDevice] as PLCController; ScannerObjectTeachingControlBoxViewModel = new UCScannerObjectTeachingControlBoxViewModel(_Aurora); // For LASA image update, after scout _Aurora.EventObservable.AsObservable(AuroraSysEvent.SYS_SETTING_CHANGED) .ObserveOnDispatcher() .Subscribe(OnSettingReloaded); // New, Delete, Copy, Rename _Aurora.EventObservable.AsObservable(AuroraSysEvent.SYS_RECIPE_ENTRY_CHANGED) .ObserveOnDispatcher() .Subscribe(OnRecipeEntryChanged); _Aurora.EventObservable.AsObservable(AuroraSysEvent.SYS_RECIPE_ACTIVATED) .ObserveOnDispatcher() .Subscribe(OnActivatedRecipe); _Aurora.EventObservable.AsObservable(CommonEventIds.EVENT_EQUIPMENT_STATUS_CHANGE) .Subscribe(x => OnChangedEquipmentStatus()); RecipeHelper.OnActiveReloaded(); CommonHelper.UpdateAutoRunPage(); } private object OnChangedEquipmentStatus() { IsManualStatus = Status.EquipmentStatus == eEqpStatus.Manual; //_Aurora.RecipeManager.SaveLock(CommonRecipeIds.ScannerObjectTeaching, !IsManualStatus); return null; } private void OnSettingReloaded(object obj) { if (obj is EventMessage msg && msg.Param is string target && msg != null) { if (target != CommonSettingIds.SystemParameter) { Log.I($"Target is not {CommonSettingIds.SystemParameter} Update Skip"); return; } if (msg.From == "SeqAutoRunLHS_New" || msg.From == "SeqAutoRunPrismaticScanner_New" || msg.From == "UCMainAutoRunViewModel") { Log.I($"SystemParameter Update Skip >> From({msg.From})"); return; } } // ScannerCanvasCtrlTeaching Update CommonHelper.GetMainPage().ReloadSetting(); } private void OnRecipeEntryChanged(object obj) { Log.I("SYS_RECIPE_ENTRY_CHANGED, OnRecipeEntryChanged"); if (obj == null || !(obj is EventMessage msg)) { return; } if (msg.Param is RecipeEntryChangedParam param) { if (param.AddedId != -1) { //New var recipe = _RecipeManager.Recipes().FirstOrDefault(x => x.Id == param.AddedId); if (recipe == null) return; RecipeHelper.SelectedRecipe = (recipe.Id, recipe.Name); RecipeHelper.SaveRecipe(recipe.Name, includeModel: false); } else if (param.RemovedId != -1) { //Remove } else if (param.CopiedToId != -1 && param.CopiedFromId != -1) { //Copy } else if (param.RenameNewId != -1 && param.RenameOldId != -1) { //Rename } else { string stringFormat = string.Format($"Error : OnRecipeEntryChanged\n" + $"[Add] [{param.AddedId}]\n" + $"[Remove] [{param.RemovedId}]\n" + $"[Copy] [{param.CopiedFromId}] [{param.CopiedToId}]\n" + $"[Rename] [{param.RenameOldId}] [{param.RenameNewId}]"); MessageUtil.CreateAndShowMessageDialog("Error", stringFormat); } } } public void OnActivatedRecipe(object obj) { Log.D("SYS_RECIPE_ACTIVATED OnActivatedRecipe"); if (obj == null || !(obj is EventMessage msg)) { return; } // @deprecated temporary support // Recipe를 선택하는데 Z축 동작이 되는 것은 굉장히 위험한 상황이다. // 한시적으로만 사용한다.. //LHS 라인에서 Recipe Rename시 Mdoel이 Activate 되지 않아서 Rename시가 아니라 //Recipe Active시 Model Active 될 수 있도로 추가 string modelname = _ModelManager.Models().FirstOrDefault(); if (modelname.Trim() == "" || modelname == null) { string stringFormat = string.Format($"Error : Model, 현재 Recipe에 Model list가 없습니다."); MessageUtil.CreateAndShowMessageDialog("Error", stringFormat); return; } _ModelManager.ActivateModel(modelname); Log.I($"Activate Model Name : {modelname}"); var activeRecipe = _RecipeManager.ActivatedRecipe(); RecipeHelper.SaveRecipe(activeRecipe.Name); // Aurora에서 제공하는 이벤트(SYS_RECIPE_ACTIVATED)를 체인으로 사용하면 동작(Aurora가 저장 후 LASA가 저장하는)에 대한 우선순위가 보장이 안되기 때문에 _Aurora.EventPublisher.Publish(new EventMessage("OnActivatedRecipe", CommonEventIds.EVENT_CHANGE_RECIPE_INFO, activeRecipe)); Log.V("CommonEventIds.EVENT_CHANGE_RECIPE_INFO from [OnActivatedRecipe]"); } public void OnChanged((int id, string name) recipe) { RecipeHelper.SelectedRecipe = recipe; RecipeHelper.ReloadRecipe(recipe.name); _RecipeBeforeChanged = RecipeHelper.getRecipeInfo(recipe.name); } public void Reloaded((int id, string name) recipe) { RecipeHelper.SelectedRecipe = recipe; RecipeHelper.ReloadRecipe(recipe.name); } public void OnModelSelectChanged(string modelName) { //throw new NotImplementedException(); } public bool PreSaved(int id, string recipeName) { try { if (ApplicationExt.PermissionLevel > (uint)PermissionLevel.LEVEL3) { MessageUtil.ShowErrorToast("Engineer 권한으로 로그인 하시기 바랍니다.", Log); return false; } if (!IsManualStatus) { MessageUtil.ShowErrorToast("Auto 상태에서 레시피 변경 불가", Log); return false; } return true; } catch (Exception ex) { Log.E($"PreSaved failed: {ex}"); } return false; } public void OnSaved(int id, string recipeName) { if (string.IsNullOrWhiteSpace(RecipeHelper.SelectedRecipe.name)) { return; } RecipeHelper.SaveRecipe(RecipeHelper.SelectedRecipe.name); var ChangedRecipe = RecipeHelper.getRecipeInfo(RecipeHelper.SelectedRecipe.name); var diffs = new ObservableCollection(); for (int i = 0; i < 3; i++) { CompareHelper.Fill(_RecipeBeforeChanged.ReadOnlyScanParams[i], ChangedRecipe.ReadOnlyScanParams[i], diffs, new CompareHelper.FieldSpec(nameof(ScannerParam.MarkDelay), x => x.MarkDelay), new CompareHelper.FieldSpec(nameof(ScannerParam.JumpDelay), x => x.JumpDelay), new CompareHelper.FieldSpec(nameof(ScannerParam.LaserOnDelay), x => x.LaserOnDelay), new CompareHelper.FieldSpec(nameof(ScannerParam.LaserOffDelay), x => x.LaserOffDelay), new CompareHelper.FieldSpec(nameof(ScannerParam.LaserFrequency), x => x.LaserFrequency), new CompareHelper.FieldSpec(nameof(ScannerParam.NumberOfCount), x => x.NumberOfCount) ); if (diffs.Count > 0) { Log.FuncI($"ScanParameter{i + 1} Recipe Changed"); _Aurora.RecipeManager.RchHandler().AppendChangedItem(RecipeHelper.SelectedRecipe.name + $"-ScanParam{i + 1}", diffs); foreach (var diff in diffs) Log.V($"{diff.ToString()}"); } } _RecipeBeforeChanged = ChangedRecipe; var activeRecipe = _RecipeManager.ActivatedRecipe(); if (RecipeHelper.SelectedRecipe.id == activeRecipe.Id) { CommonHelper.UpdateAutoRunPage(); // Aurora에서 제공하는 이벤트(SYS_RECIPE_ITEM_CHANGED)를 체인으로 사용하면 동작(Aurora가 저장 후 LASA가 저장하는)에 대한 우선순위가 보장이 안되기 때문에 _Aurora.EventPublisher.Publish(new EventMessage("OnSaved", CommonEventIds.EVENT_CHANGE_RECIPE_INFO, activeRecipe)); Log.V($"CommonEventIds.EVENT_CHANGE_RECIPE_INFO from [OnSaved] RecipeName [{RecipeHelper.SelectedRecipe.name}]"); } Log.I($"Saved Recipe : [{RecipeHelper.SelectedRecipe.name}]"); } } }