using Aurora; using Aurora.Api; using Aurora.Api.Devices; using Aurora.View; using AuroraLaser; using CoreUnit.Control.UserControl.Canvas; using CoreUnit.Scanner.UserControl.ScannerCanvas; using DB.Recipe; using Hermes; using ILSOS_PrismaticGun.Alarm; using ILSOS_PrismaticGun.Device; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reactive.Linq; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Markup; using System.Windows.Media; using VisionCommon; using WeldingCommon; using WeldingCommon.Alarm; using WeldingCommon.Data; using WeldingCommon.Devices; using WeldingCommon.RMS; using WeldingCommon.Settings; using WeldingCommon.Utils; using WeldingCommon.Utils.Diff; using static AuroraPLC.PLCBase; using static ILSOS_PrismaticGun.Device.PLCControllerPrismaticGun; using static WeldingCommon.Devices.PLCController; namespace ILSOS_PrismaticGun.Recipes { public class RMSHandlerForMainWelder : RMSHandler { private const string AStageLaserWeldingRecipeNo = "AStageLaserWeldingRecipeNo"; private const string AStageLaserWeldingN2PurgeFlow = "AStageLaserWeldingN2PurgeFlow"; private const string AStageLaserWeldingPosition = "AStageLaserWeldingPosition"; private const string AStageLaserLineSpeed = "AStageLaserLineSpeed"; private const string AStageLaserCornerSpeed = "AStageLaserCornerSpeed"; private const string AStageLaserLinePowerCore = "AStageLaserLinePowerCore"; private const string AStageLaserLinePowerRing = "AStageLaserLinePowerRing"; private const string AStageLaserCornerPowerCore = "AStageLaserCornerPowerCore"; private const string AStageLaserCornerPowerRing = "AStageLaserCornerPowerRing"; private const string AStageLaserRampingPowerStarting = "AStageLaserRampingPowerStarting"; private const string AStageLaserRampingLengthStarting = "AStageLaserRampingLengthStarting"; private const string AStageLaserRampingPowerOverpath = "AStageLaserRampingPowerOverpath"; private const string AStageLaserRampingLengthOverpath = "AStageLaserRampingLengthOverpath"; private const string BStageLaserWeldingRecipeNo = "BStageLaserWeldingRecipeNo"; private const string BStageLaserWeldingN2PurgeFlow = "BStageLaserWeldingN2PurgeFlow"; private const string BStageLaserWeldingPosition = "BStageLaserWeldingPosition"; private const string BStageLaserLineSpeed = "BStageLaserLineSpeed"; private const string BStageLaserCornerSpeed = "BStageLaserCornerSpeed"; private const string BStageLaserLinePowerCore = "BStageLaserLinePowerCore"; private const string BStageLaserLinePowerRing = "BStageLaserLinePowerRing"; private const string BStageLaserCornerPowerCore = "BStageLaserCornerPowerCore"; private const string BStageLaserCornerPowerRing = "BStageLaserCornerPowerRing"; private const string BStageLaserRampingPowerStarting = "BStageLaserRampingPowerStarting"; private const string BStageLaserRampingLengthStarting = "BStageLaserRampingLengthStarting"; private const string BStageLaserRampingPowerOverpath = "BStageLaserRampingPowerOverpath"; private const string BStageLaserRampingLengthOverpath = "BStageLaserRampingLengthOverpath"; private PLCControllerPrismaticGun _plc; private SettingRmsDataList _RmsSetting; public override void RegistryDeviceHandler(IAuroraEnvironment aurora) { base.RegistryDeviceHandler(aurora); _plc = aurora.DeviceManager[CommonDeviceIds.PLCDevice] as PLCControllerPrismaticGun; _RmsSetting = aurora.SettingEntry[CommonSettingIds.RmsDatas] as SettingRmsDataList; aurora.EventObservable.AsObservable(AuroraSysEvent.SYS_RECIPE_ACTIVATED) .ObserveOnDispatcher() .Select(param => (RecipeInfo)param.Param) .Subscribe(t => UploadRecipeParameter(t.Id)); aurora.EventObservable.AsObservable(AuroraSysEvent.SYS_RECIPE_ITEM_CHANGED) .ObserveOnDispatcher() .Subscribe(UploadActivatedRecipeParameter); } private void UploadActivatedRecipeParameter(EventMessage message) { var id = _aurora.RecipeManager.ActivatedRecipe().Id; UploadRecipeParameter(id); } private bool TrySetReportData(string key, double value) { var data = getReportData(key); if (data == null) { Log.E($"RMS 데이터 항목을 찾을 수 없음: {key}"); _aurora.AlarmService.SetAlarm(AlarmCode.RMS_PAGE_SETTING_NULL); return false; } data.Value = value; return true; } private void UploadRecipeParameter(int id) { try { var RecipeStageA = _recipeEntry.RecipeItem(id, RecipeIds.StageAMainRecipe) as MainRecipe; var RecipeStageB = _recipeEntry.RecipeItem(id, RecipeIds.StageBMainRecipe) as MainRecipe; if (RecipeStageA == null || RecipeStageB == null) { Log.E($"레시피 항목 로드 실패: id={id}, StageA={RecipeStageA != null}, StageB={RecipeStageB != null}"); MessageUtil.ShowToast($"RMS 레시피 항목 로드 실패 (id={id})", Log); _aurora.AlarmService.SetAlarm(AlarmCode.RMS_PAGE_SETTING_NULL); return; } if (!TrySetReportData(AStageLaserWeldingRecipeNo, id)) return; if (!TrySetReportData(AStageLaserWeldingN2PurgeFlow, RecipeStageA.N2PressMFC)) return; if (!TrySetReportData(AStageLaserWeldingPosition, RecipeStageA.AxisZPosition)) return; if (!TrySetReportData(AStageLaserLineSpeed, RecipeStageA.StraightParam.Velocity)) return; if (!TrySetReportData(AStageLaserCornerSpeed, RecipeStageA.CurveParam.Velocity)) return; if (!TrySetReportData(AStageLaserLinePowerCore, RecipeStageA.StraightParam.CorePowerW)) return; if (!TrySetReportData(AStageLaserLinePowerRing, RecipeStageA.StraightParam.RingPowerW)) return; if (!TrySetReportData(AStageLaserCornerPowerCore, RecipeStageA.CurveParam.CorePowerW)) return; if (!TrySetReportData(AStageLaserCornerPowerRing, RecipeStageA.CurveParam.RingPowerW)) return; if (!TrySetReportData(AStageLaserRampingPowerStarting, RecipeStageA.RampingOnStartPower)) return; if (!TrySetReportData(AStageLaserRampingLengthStarting, RecipeStageA.RampingOnOverlapDist)) return; if (!TrySetReportData(AStageLaserRampingPowerOverpath, RecipeStageA.RampingOffEndPower)) return; if (!TrySetReportData(AStageLaserRampingLengthOverpath, RecipeStageA.RampingOffOverlapDist)) return; if (!TrySetReportData(BStageLaserWeldingRecipeNo, id)) return; if (!TrySetReportData(BStageLaserWeldingN2PurgeFlow, RecipeStageB.N2PressMFC)) return; if (!TrySetReportData(BStageLaserWeldingPosition, RecipeStageB.AxisZPosition)) return; if (!TrySetReportData(BStageLaserLineSpeed, RecipeStageB.StraightParam.Velocity)) return; if (!TrySetReportData(BStageLaserCornerSpeed, RecipeStageB.CurveParam.Velocity)) return; if (!TrySetReportData(BStageLaserLinePowerCore, RecipeStageB.StraightParam.CorePowerW)) return; if (!TrySetReportData(BStageLaserLinePowerRing, RecipeStageB.StraightParam.RingPowerW)) return; if (!TrySetReportData(BStageLaserCornerPowerCore, RecipeStageB.CurveParam.CorePowerW)) return; if (!TrySetReportData(BStageLaserCornerPowerRing, RecipeStageB.CurveParam.RingPowerW)) return; if (!TrySetReportData(BStageLaserRampingPowerStarting, RecipeStageB.RampingOnStartPower)) return; if (!TrySetReportData(BStageLaserRampingLengthStarting, RecipeStageB.RampingOnOverlapDist)) return; if (!TrySetReportData(BStageLaserRampingPowerOverpath, RecipeStageB.RampingOffEndPower)) return; if (!TrySetReportData(BStageLaserRampingLengthOverpath, RecipeStageB.RampingOffOverlapDist)) return; //Write Parameter UploadRmsParameter(); } catch (Exception ex) { Log.E($"UploadRecipeParameter 예외: {ex.Message}"); MessageUtil.ShowToast($"RMS 파라미터 업로드 중 오류 발생", Log); _aurora.AlarmService.SetAlarm(AlarmCode.RMS_PAGE_SETTING_NULL); } } // Server(PLC) => Client(Local PC) public override void OnParameterReadRequest(EventMessage message) { Task.Run(() => { if (_setting.IgnoreRMS) { MessageUtil.ShowToast($"Not Used RMS Recipe", Log); _aurora.AlarmService.SetAlarm(AlarmCode.RMS_NOT_USED_OPTION); return; } // Read Parameter if (UpdateRmsParameter() != E1.OK) { MessageUtil.ShowToast($"RMS Parameter Read Fail", Log); _aurora.AlarmService.SetAlarm(AlarmCode.RMS_RECIPE_EDIT_REQUEST_RESPONSE_TIMEOUT); return; } // RMS Recipe Check var recipeId = getReportData(AStageLaserWeldingRecipeNo).readValue(-1); var recipe = _recipeEntry.Recipes().FirstOrDefault(x => x.Id == recipeId); if (recipe == null) { MessageUtil.ShowToast($"{recipeId}번 레시피 없음", Log); _aurora.AlarmService.SetAlarm(AlarmCode.RMS_RECIPE_EDIT_REQUEST_RESPONSE_TIMEOUT); return; } var RecipeStageA = _recipeEntry.RecipeItem(recipeId, RecipeIds.StageAMainRecipe) as MainRecipe; var RecipeStageB = _recipeEntry.RecipeItem(recipeId, RecipeIds.StageBMainRecipe) as MainRecipe; var RecipeBeforeChangedStageA = RecipeStageA.Clone() as MainRecipe; var RecipeBeforeChangedStageB = RecipeStageB.Clone() as MainRecipe; RecipeStageA.N2PressMFC = getReportData(AStageLaserWeldingN2PurgeFlow).readValue(RecipeStageA.N2PressMFC); RecipeStageA.AxisZPosition = getReportData(AStageLaserWeldingPosition).readValue(RecipeStageA.AxisZPosition); RecipeStageA.StraightParam.Velocity = getReportData(AStageLaserLineSpeed).readValue(RecipeStageA.StraightParam.Velocity); RecipeStageA.CurveParam.Velocity = getReportData(AStageLaserCornerSpeed).readValue(RecipeStageA.CurveParam.Velocity); RecipeStageA.StraightParam.CorePowerW = getReportData(AStageLaserLinePowerCore).readValue(RecipeStageA.StraightParam.CorePowerW); RecipeStageA.StraightParam.RingPowerW = getReportData(AStageLaserLinePowerRing).readValue(RecipeStageA.StraightParam.RingPowerW); RecipeStageA.CurveParam.CorePowerW = getReportData(AStageLaserCornerPowerCore).readValue(RecipeStageA.CurveParam.CorePowerW); var CurvRingPowerStageA = getReportData(AStageLaserCornerPowerRing).readValue(RecipeStageA.CurveParam.RingPowerW); RecipeStageA.RampingOnStartPower = getReportData(AStageLaserRampingPowerStarting).readValue(RecipeStageA.RampingOnStartPower); RecipeStageA.RampingOnOverlapDist = getReportData(AStageLaserRampingLengthStarting).readValue(RecipeStageA.RampingOnOverlapDist); RecipeStageA.RampingOffEndPower = getReportData(AStageLaserRampingPowerOverpath).readValue(RecipeStageA.RampingOffEndPower); RecipeStageA.RampingOffOverlapDist = getReportData(AStageLaserRampingLengthOverpath).readValue(RecipeStageA.RampingOffOverlapDist); RecipeStageB.N2PressMFC = getReportData(BStageLaserWeldingN2PurgeFlow).readValue(RecipeStageB.N2PressMFC); RecipeStageB.AxisZPosition = getReportData(BStageLaserWeldingPosition).readValue(RecipeStageB.AxisZPosition); RecipeStageB.StraightParam.Velocity = getReportData(BStageLaserLineSpeed).readValue(RecipeStageB.StraightParam.Velocity); RecipeStageB.CurveParam.Velocity = getReportData(BStageLaserCornerSpeed).readValue(RecipeStageB.CurveParam.Velocity); RecipeStageB.StraightParam.CorePowerW = getReportData(BStageLaserLinePowerCore).readValue(RecipeStageB.StraightParam.CorePowerW); RecipeStageB.StraightParam.RingPowerW = getReportData(BStageLaserLinePowerRing).readValue(RecipeStageB.StraightParam.RingPowerW); RecipeStageB.CurveParam.CorePowerW = getReportData(BStageLaserCornerPowerCore).readValue(RecipeStageB.CurveParam.CorePowerW); var CurvRingPowerStageB = getReportData(BStageLaserCornerPowerRing).readValue(RecipeStageB.CurveParam.RingPowerW); RecipeStageB.RampingOnStartPower = getReportData(BStageLaserRampingPowerStarting).readValue(RecipeStageB.RampingOnStartPower); RecipeStageB.RampingOnOverlapDist = getReportData(BStageLaserRampingLengthStarting).readValue(RecipeStageB.RampingOnOverlapDist); RecipeStageB.RampingOffEndPower = getReportData(BStageLaserRampingPowerOverpath).readValue(RecipeStageB.RampingOffEndPower); RecipeStageB.RampingOffOverlapDist = getReportData(BStageLaserRampingLengthOverpath).readValue(RecipeStageB.RampingOffOverlapDist); // Recipe Save var editRequestRecipe = _recipeEntry.Recipes().FirstOrDefault(x => x.Id == recipeId); _aurora.RecipeManager.SaveRecipeItem(editRequestRecipe, RecipeIds.StageAMainRecipe, RecipeStageA); _aurora.RecipeManager.SaveRecipeItem(editRequestRecipe, RecipeIds.StageBMainRecipe, RecipeStageB); //Compare 추가 var diffs = new ObservableCollection(); CompareHelper.Fill(RecipeBeforeChangedStageA, RecipeStageA, diffs, new CompareHelper.FieldSpec(nameof(MainRecipe.N2PressMFC), x => x.N2PressMFC), new CompareHelper.FieldSpec(nameof(MainRecipe.AxisZPosition), x => x.AxisZPosition), new CompareHelper.FieldSpec(nameof(MainRecipe.StraightParam.Velocity), x => x.StraightParam.Velocity), new CompareHelper.FieldSpec(nameof(MainRecipe.CurveParam.Velocity), x => x.CurveParam.Velocity), new CompareHelper.FieldSpec(nameof(MainRecipe.StraightParam.CorePowerW), x => x.StraightParam.CorePowerW), new CompareHelper.FieldSpec(nameof(MainRecipe.StraightParam.RingPowerW), x => x.StraightParam.RingPowerW), new CompareHelper.FieldSpec(nameof(MainRecipe.CurveParam.CorePowerW), x => x.CurveParam.CorePowerW), new CompareHelper.FieldSpec(nameof(MainRecipe.RampingOnStartPower), x => x.RampingOnStartPower), new CompareHelper.FieldSpec(nameof(MainRecipe.RampingOnOverlapDist), x => x.RampingOnOverlapDist), new CompareHelper.FieldSpec(nameof(MainRecipe.RampingOffEndPower), x => x.RampingOffEndPower), new CompareHelper.FieldSpec(nameof(MainRecipe.RampingOffOverlapDist), x => x.RampingOffOverlapDist) ); if(diffs.Count > 0) { Log.FuncI("StageA Recipe Changed"); _aurora.RecipeManager.RchHandler().AppendChangedItem(recipe.Name + "-StageA", diffs); foreach (var diff in diffs) Log.V($"{diff.ToString()}"); } CompareHelper.Fill(RecipeBeforeChangedStageB, RecipeStageB, diffs, new CompareHelper.FieldSpec(nameof(MainRecipe.N2PressMFC), x => x.N2PressMFC), new CompareHelper.FieldSpec(nameof(MainRecipe.AxisZPosition), x => x.AxisZPosition), new CompareHelper.FieldSpec(nameof(MainRecipe.StraightParam.Velocity), x => x.StraightParam.Velocity), new CompareHelper.FieldSpec(nameof(MainRecipe.CurveParam.Velocity), x => x.CurveParam.Velocity), new CompareHelper.FieldSpec(nameof(MainRecipe.StraightParam.CorePowerW), x => x.StraightParam.CorePowerW), new CompareHelper.FieldSpec(nameof(MainRecipe.StraightParam.RingPowerW), x => x.StraightParam.RingPowerW), new CompareHelper.FieldSpec(nameof(MainRecipe.CurveParam.CorePowerW), x => x.CurveParam.CorePowerW), new CompareHelper.FieldSpec(nameof(MainRecipe.RampingOnStartPower), x => x.RampingOnStartPower), new CompareHelper.FieldSpec(nameof(MainRecipe.RampingOnOverlapDist), x => x.RampingOnOverlapDist), new CompareHelper.FieldSpec(nameof(MainRecipe.RampingOffEndPower), x => x.RampingOffEndPower), new CompareHelper.FieldSpec(nameof(MainRecipe.RampingOffOverlapDist), x => x.RampingOffOverlapDist) ); if (diffs.Count > 0) { Log.FuncI("StageB Recipe Changed"); _aurora.RecipeManager.RchHandler().AppendChangedItem(recipe.Name + "-StageB", diffs); foreach (var diff in diffs) Log.V($"{diff.ToString()}"); } // Activated Recipe를 자동으로 변경 >> ActivedRecipe Change Event를 통해서 써주기까지 함 var preActivatedRecipe = _aurora.RecipeManager.ActivatedRecipe(); _aurora.RecipeManager.ActivateRecipe(recipe.Id, "RMS Request"); MessageUtil.ShowToast($"RMS Change Recipe Parameter & Activated Recipe ( {preActivatedRecipe.Id} -> {recipe.Id} )", Log); // Complete if (!ReportChangeConfirm()) { MessageUtil.ShowToast($"RMS Change Recipe Ack Timeout", Log); _aurora.AlarmService.SetAlarm(AlarmCode.RMS_RECIPE_EDIT_REQUEST_RESPONSE_TIMEOUT); return; } MessageUtil.ShowToast($"Complete OnParameterReadRequest", Log); }); } } }