using Aurora; using Aurora.Api; using Aurora.Api.Devices; using Aurora.Api.Manager; using Aurora.Framework.Core; using Aurora.Util.HislogPlus; using Aurora.View; using AuroraACS; using AuroraHeightSensor; using CoreUnit.Scanner.UserControl.ScannerCanvas; using DB.Recipe; using Hermes; using Hermes.Functional; using ILSOS_PrismaticGun.Alarm; using ILSOS_PrismaticGun.Device.ACS; using ILSOS_PrismaticGun.Process; using ILSOS_PrismaticGun.Recipes; using ILSOS_PrismaticGun.Settings; using OpenCvSharp.Dnn; using PropertyTools.Wpf; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Reactive.Linq; using System.Runtime.Remoting.Contexts; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Forms; using System.Windows.Input; using VisionCommon; using WeldingCommon; using WeldingCommon.Alarm; using WeldingCommon.Settings; using WeldingCommon.Utils; using WeldingCommon.Utils.Diff; using DelegateCommand = Aurora.View.DelegateCommand; namespace ILSOS_PrismaticGun.Views.Recipe { internal class UCMainRecipeViewModel : NotifyPropertyChangedBase, IRecipeViewModel { private Logger Log = new Logger("UCMainRecipeViewModel"); private readonly IAuroraEnvironment _env; public ICommand CMD_VisibleChanged { get; } public ICommand CMD_GetPosition { get; } public ICommand CMD_MovePosition { get; } public ICommand CMD_GetHeight { get; } public ICommand CMD_AddHeightParam { get; } public ICommand CMD_DeleteHeightParam { get; } public double JogMm { get => _JogMm; set { if (value > 3) { System.Windows.MessageBox.Show("3보다 클 수 없습니다."); SetProperty(ref _JogMm, 3); return; } SetProperty(ref _JogMm, value); } } private double _JogMm = 0.05; public ICommand CMD_YP { get; } public ICommand CMD_XM { get; } public ICommand CMD_XP { get; } public ICommand CMD_YM { get; } public bool IsManualStatus { get => _IsManualStatus; set => SetProperty(ref _IsManualStatus, value); } private bool _IsManualStatus = true; public bool IsDoorLock { get => _IsDoorLock; set => SetProperty(ref _IsDoorLock, value); } private bool _IsDoorLock = true; private readonly IRecipeManager _Manager; private (int id, string name) _RecipeId; private IPrismaticGunACS _motion; private PrismaticGunACS _acs; private ACSMotor _motorX; private ACSMotor _motorY; private HeightSensor _height; // OutputType 콤보박스 항목 목록 (eOutType 열거형 전체) // 파라미터 패널 전환은 XAML DataTemplate + DataTrigger로 처리 — Visibility 속성 불필요 public List MotorIDList { get; } = Enum.GetValues(typeof(MainRecipe.eOutType)).Cast().ToList(); /// OutputType 콤보박스 편집 가능 여부. lockedOutputType 지정 시 false. public bool IsOutputTypeEditable { get; private set; } = true; private readonly MainRecipe.eOutType? _lockedOutputType; public MainRecipe Recipe { get => _Recipe; private set => SetProperty(ref _Recipe, value); } private MainRecipe _Recipe; private MainRecipe _RecipeBeforeChanged; public string _recipe; public HeightMeareUnit SelectedHeightParam { get => _SelectedHeightParam; set => SetProperty(ref _SelectedHeightParam, value); } private HeightMeareUnit _SelectedHeightParam; public string PositionSettingGuide { get; set; } public string LaserOnOffRamping { get; set; } public string HeightSettingGuide { get; set; } public bool EnableControlForRMS { get => _DisableControlForRMS; set => SetProperty(ref _DisableControlForRMS, value); } private bool _DisableControlForRMS = false; private readonly eStage stage; public UCMainRecipeViewModel(IAuroraEnvironment auroraEnv, (int, string) recipe, IRecipeItem recipeItem, string recipeId, MainRecipe.eOutType? lockedOutputType = null) { _env = auroraEnv; _lockedOutputType = lockedOutputType; if (lockedOutputType.HasValue) IsOutputTypeEditable = false; _motion = _acs = _env.DeviceManager[DeviceIds.ACS] as PrismaticGunACS; _RecipeId = recipe; _recipe = recipeId; _Manager = auroraEnv.RecipeManager; var setting = _env.SettingEntry[CommonSettingIds.SystemParameter] as WeldingCommon.Settings.SystemParameter; PositionSettingGuide = Path.Combine(setting.ResourceFolderPath, "TeachingPosition.jpg"); LaserOnOffRamping = Path.Combine(setting.ResourceFolderPath, "LaserOnOff.jpg"); HeightSettingGuide = Path.Combine(setting.ResourceFolderPath, "HeightMeasure.jpg"); if (recipeId.Contains("A")) { stage = eStage.A; _motorX = _env.DeviceManager[MotorIds.ALineX] as ACSMotor; _motorY = _env.DeviceManager[MotorIds.ALineY] as ACSMotor; } else { stage = eStage.B; _motorX = _env.DeviceManager[MotorIds.BLineX] as ACSMotor; _motorY = _env.DeviceManager[MotorIds.BLineY] as ACSMotor; } _height = _env.DeviceManager[DeviceIds.HeightSensor] as HeightSensor; Recipe = recipeItem as MainRecipe; CMD_VisibleChanged = new DelegateCommand(VisibleChanged); CMD_GetPosition = new DelegateCommand(GetPosition); CMD_GetHeight = new DelegateCommand(GetHeight); CMD_MovePosition = new DelegateCommand(MovePosition); //CMD_AddHeightParam = new DelegateCommand(AddHeightParam); //CMD_DeleteHeightParam = new DelegateCommand(DeleteHeightParam); CMD_YP = new DelegateCommand(OnYPlus); CMD_XM = new DelegateCommand(OnXMinus); CMD_XP = new DelegateCommand(OnXPlus); CMD_YM = new DelegateCommand(OnYMinus); _env.EventObservable.AsObservable(CommonEventIds.EVENT_EQUIPMENT_STATUS_CHANGE) .Subscribe(x => OnChangedEquipmentStatus()); _env.EventObservable.AsObservable(CommonEventIds.EVENT_CHANGE_DOOR_LOCK) .Where(param => param.Param is bool && param.Param != null) .Select(param => (bool)param.Param) .Subscribe(param => IsDoorLock = !param); } private object OnChangedEquipmentStatus() { IsManualStatus = Status.EquipmentStatus == eEqpStatus.Manual; //_env.RecipeManager.SaveLock(_recipe, !IsManualStatus); return null; } private void OnYPlus(object obj) { if (!_acs.IsActivated) { System.Windows.MessageBox.Show("ACS Deactivated"); return; } _motorY.SetTargetPos(JogMm, TargetPosType.REL); _motorY.SetMoveVelocityImm(Speed.L); _motorY.Move(); } private void OnXMinus(object obj) { if (!_acs.IsActivated) { System.Windows.MessageBox.Show("ACS Deactivated"); return; } _motorX.SetTargetPos(-JogMm, TargetPosType.REL); _motorX.SetMoveVelocityImm(Speed.L); _motorX.Move(); } private void OnXPlus(object obj) { if (!_acs.IsActivated) { System.Windows.MessageBox.Show("ACS Deactivated"); return; } _motorX.SetTargetPos(JogMm, TargetPosType.REL); _motorX.SetMoveVelocityImm(Speed.L); _motorX.Move(); } private void OnYMinus(object obj) { if (!_acs.IsActivated) { System.Windows.MessageBox.Show("ACS Deactivated"); return; } _motorY.SetTargetPos(-JogMm, TargetPosType.REL); _motorY.SetMoveVelocityImm(Speed.L); _motorY.Move(); } private void GetPosition(object obj) { if (!_acs.IsActivated) { System.Windows.MessageBox.Show("ACS Deactivated"); return; } if (System.Windows.MessageBox.Show("위치를 가져오시겠습니까?", "Get Position", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { if (obj is ProcessUnit param) { param.PosX = _motorX.GetActualPos(); param.PosY = _motorY.GetActualPos(); } else if (obj is HeightMeareUnit measureUnit) { measureUnit.PosX = _motorX.GetActualPos(); measureUnit.PosY = _motorY.GetActualPos(); } } } private void GetHeight(object obj) { if(!_height.IsActivated) System.Windows.MessageBox.Show("HeightSensor Deactivated"); _height.MeasureAll(out List val); if (val == null || val.Count < 4) { System.Windows.MessageBox.Show("측정 실패, 장치가 올바르게 설치되지 않았습니다."); return; } MessageUtil.CreateAndShowMessageDialog("Height", $"높이센서 측정값 : {val[(2 * (int)stage)]} / {val[(2 * (int)stage) + 1]}"); } //private void AddHeightParam(object obj) //{ // if (Recipe.HeightSensorMeasurePoints.Count >= 10) { // MessageUtil.CreateAndShowMessageDialog("Fail", $"List Limit Over [Current:{Recipe.HeightSensorMeasurePoints.Count} Max: 5]"); // return; // } // if (SelectedHeightParam == null) { // Recipe.HeightSensorMeasurePoints.Add(new HeightMeareUnit() { Index = Recipe.HeightSensorMeasurePoints.Count + 1 }); // return; // } // Recipe.HeightSensorMeasurePoints.Insert(Recipe.HeightSensorMeasurePoints.IndexOf(SelectedHeightParam) + 1, new HeightMeareUnit()); // for (int i = 0, j = 1; i < Recipe.HeightSensorMeasurePoints.Count; i++, j++) // Recipe.HeightSensorMeasurePoints[i].Index = j; //} //private void DeleteHeightParam(object obj) //{ // if (SelectedHeightParam == null) // return; // Recipe.HeightSensorMeasurePoints.Remove(SelectedHeightParam); // for (int i = 0, j = 1; i < Recipe.HeightSensorMeasurePoints.Count; i++, j++) // Recipe.HeightSensorMeasurePoints[i].Index = j; //} public bool CheckValidPosition(double xPos, double yPos) { if (!_acs.IsActivated) return false; return false; } private void MovePosition(object obj) { if (!_acs.IsActivated) return; if (System.Windows.MessageBox.Show("이동하시겠습니까?", "Motion Move", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { if (obj is ProcessUnit param) { var teachingSetting = _env.SettingEntry[SettingIds.TeachingPos] as TeachingPositionSetting; var EnableLoadNegX = teachingSetting.Get(stage, ePLCEnableLimitPosition.LoadNegativeLimit).AxisX; var EnableUnloadPositX = teachingSetting.Get(stage, ePLCEnableLimitPosition.UnloadPositiveLimit).AxisX; if(EnableLoadNegX > _motorX.GetActualPos() || _motorX.GetActualPos() > EnableUnloadPositX){ System.Windows.MessageBox.Show($"현재위치({_motorX.GetActualPos()})에서 이동이 불가합니다. 가능영역({EnableLoadNegX} ~ {EnableUnloadPositX})"); return; } _motorX.SetTargetPos(param.PosX, TargetPosType.ABS); _motorX.SetMoveVelocityImm(Speed.L); _motorX.Move(); _motorY.SetTargetPos(param.PosY, TargetPosType.ABS); _motorY.SetMoveVelocityImm(Speed.L); _motorY.Move(); } else if(obj is HeightMeareUnit measureUnit) { var teachingSetting = _env.SettingEntry[SettingIds.TeachingPos] as TeachingPositionSetting; var EnableNegativePos = teachingSetting.Get(stage, ePLCEnableLimitPosition.LoadNegativeLimit).AxisX; var PLCLoadEnableOffPosition = measureUnit.PosX <= EnableNegativePos; var MoveDirectionNeg = measureUnit.PosX + 0.1 < _motorX.GetActualPos(); var XList = Recipe.HeightSensorMeasurePoints.Select(t => t.PosX).ToList(); var minValue = XList.Min(); if (_motorX.GetActualPos() < minValue - 0.01) { System.Windows.MessageBox.Show($"현재위치({_motorX.GetActualPos()})가 측정위치의 최소값({minValue})보다 작은 경우, 이동이 불가합니다."); return; } if (PLCLoadEnableOffPosition && MoveDirectionNeg) { if (!MessageUtil.ShowYesNoMessageDialog("측정 실패", $"PLC 이재기가 내려올 경우 충돌 위치 입니다. 이동하시겠습니까?")) return; } _motorX.SetTargetPos(measureUnit.PosX, TargetPosType.ABS); _motorX.SetMoveVelocityImm(Speed.L); _motorX.Move(); _motorY.SetTargetPos(measureUnit.PosY, TargetPosType.ABS); _motorY.SetMoveVelocityImm(Speed.L); _motorY.Move(); } } } private void VisibleChanged(object obj) { bool visible = (bool)obj; if (visible){ Recipe.UpdateCurveRingPower(); } else ; } public void OnChanged((int id, string name) recipe) { Recipe = _Manager.RecipeItem(recipe.id, _recipe) as MainRecipe; if (_lockedOutputType.HasValue) Recipe.OutputType = _lockedOutputType.Value; _RecipeBeforeChanged = Recipe.Clone() as MainRecipe; } public void Reloaded((int id, string name) recipe) { Recipe = _Manager.RecipeItem(recipe.id, _recipe) as MainRecipe; if (_lockedOutputType.HasValue) Recipe.OutputType = _lockedOutputType.Value; } public void OnModelSelectChanged(string modelName) { } 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) { var recipe = _Manager.RecipeItem(id, recipeName) as MainRecipe; var diffs = new ObservableCollection(); CompareHelper.Fill(_RecipeBeforeChanged, recipe, diffs, new CompareHelper.FieldSpec("Acceleration", x => x.WeldingAcc), new CompareHelper.FieldSpec("StartPosX", x => x.StartPos.PosX), new CompareHelper.FieldSpec("StartPosY", x => x.StartPos.PosY), new CompareHelper.FieldSpec("EndPosX", x => x.EndPos.PosX), new CompareHelper.FieldSpec("EndPosY", x => x.EndPos.PosY), new CompareHelper.FieldSpec("LaserOnPosition", x => x.LaserOnPosition), new CompareHelper.FieldSpec("RampingOffStartPos", x => x.RampingOffStartPos), new CompareHelper.FieldSpec(nameof(MainRecipe.Arc1), x => x.Arc1.Size), new CompareHelper.FieldSpec(nameof(MainRecipe.Arc2), x => x.Arc2.Size), new CompareHelper.FieldSpec(nameof(MainRecipe.Arc3), x => x.Arc3.Size), new CompareHelper.FieldSpec(nameof(MainRecipe.Arc4), x => x.Arc4.Size), new CompareHelper.FieldSpec("TeachingPos1X", x => x.Units[0].PosX), new CompareHelper.FieldSpec("TeachingPos1Y", x => x.Units[0].PosY), new CompareHelper.FieldSpec("TeachingPos2X", x => x.Units[1].PosX), new CompareHelper.FieldSpec("TeachingPos2Y", x => x.Units[1].PosY), new CompareHelper.FieldSpec("TeachingPos3X", x => x.Units[2].PosX), new CompareHelper.FieldSpec("TeachingPos3Y", x => x.Units[2].PosY), new CompareHelper.FieldSpec("TeachingPos4X", x => x.Units[3].PosX), new CompareHelper.FieldSpec("TeachingPos4Y", x => x.Units[3].PosY), new CompareHelper.FieldSpec("TeachingPos5X", x => x.Units[4].PosX), new CompareHelper.FieldSpec("TeachingPos5Y", x => x.Units[4].PosY), new CompareHelper.FieldSpec("TeachingPos6X", x => x.Units[5].PosX), new CompareHelper.FieldSpec("TeachingPos6Y", x => x.Units[5].PosY), new CompareHelper.FieldSpec("TeachingPos7X", x => x.Units[6].PosX), new CompareHelper.FieldSpec("TeachingPos7Y", x => x.Units[6].PosY), new CompareHelper.FieldSpec("TeachingPos8X", x => x.Units[7].PosX), new CompareHelper.FieldSpec("TeachingPos8Y", x => x.Units[7].PosY) ); if (diffs.Count > 0) { Log.FuncI($"Stage{stage.ToString()} Recipe Changed"); var recipeInfo = _Manager.Recipes().FirstOrDefault(x => x.Id == id); _Manager.RchHandler().AppendChangedItem(recipeInfo.Name + $"-Stage{stage.ToString()}", diffs); foreach (var diff in diffs) Log.V($"{diff.ToString()}"); } _RecipeBeforeChanged = recipe.Clone() as MainRecipe; } } }