using Aurora; using Aurora.Api; using Aurora.Api.Devices; using Aurora.Util.HislogPlus; using Aurora.View; using AuroraLaser; using CoreUnit.Control.UserControl.Canvas; using CoreUnit.Scanner.UserControl.ScannerCanvas; using DB.Recipe; using GUI; using Hermes; using ILSOS_PrismaticScanner.Alarm; using ILSOS_PrismaticScanner.Device; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; using System.Reactive.Linq; using System.Reflection; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; 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_PrismaticScanner.Device.PLCControllerPrismaticScanner; namespace ILSOS_PrismaticScanner.Recipes { public class RMSHandlerForScanner : RMSHandler { private const string RecipeNo = "RecipeNo"; //$"{nameof(param.MarkSpeed)}_{parameterNo}" private PLCControllerPrismaticScanner _plc; private SettingRmsDataList _RmsSetting; public override void RegistryDeviceHandler(IAuroraEnvironment aurora) { base.RegistryDeviceHandler(aurora); _plc = aurora.DeviceManager[CommonDeviceIds.PLCDevice] as PLCControllerPrismaticScanner; _RmsSetting = aurora.SettingEntry[CommonSettingIds.RmsDatas] as SettingRmsDataList; // Aurora에서 제공하는 이벤트를 체인으로 사용하면 동작(Aurora가 저장 후 LASA가 저장하는)에 대한 우선순위가 보장이 안되기 때문에 aurora.EventObservable.AsObservable(CommonEventIds.EVENT_CHANGE_RECIPE_INFO) .ObserveOnDispatcher() .Select(param => (RecipeInfo)param.Param) .Subscribe(OnUpdateCurrentActivatedRecipe); } private void OnUpdateCurrentActivatedRecipe(RecipeInfo info) { RecipeHelper.ReloadRecipe(info.Name); UploadActivatedRecipeParameter(); } private bool TrySetReportData(string key, double value) { var data = getReportData(key); if (data == null) { Log.E($"RMS 데이터 항목을 찾을 수 없음: {key}"); MessageUtil.ShowToast($"RMS 설정 항목 누락: {key}", Log); _aurora.AlarmService.SetAlarm(AlarmCode.RMS_PAGE_SETTING_NULL); return false; } data.Value = value; return true; } private void UploadActivatedRecipeParameter() { try { // PC에 저장된 데이터를 PLC에 전달 for (int i = 0; i < 3; i++) { if (!ApplyParamToReport(ScannerCanvasUserCtrl.ScannerParams[i], i)) return; } //Write Parameter UploadRmsParameter(); } catch (Exception ex) { Log.E($"UploadActivatedRecipeParameter 예외: {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 recipeNoData = getReportData(RecipeNo); if (recipeNoData == null) { MessageUtil.ShowToast($"RMS 설정 항목 누락: {RecipeNo}", Log); _aurora.AlarmService.SetAlarm(AlarmCode.RMS_PAGE_SETTING_NULL); return; } int recipeId = recipeNoData.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 RecipeBeforeChanged = RecipeHelper.getRecipeInfo(recipe.Name); // Recipe Load Application.Current.Dispatcher.Invoke(() => { RecipeHelper.ReloadRecipe(recipe.Name); }); for (int i = 0; i < 3; i++) { if (!ApplyReportToParam(ScannerCanvasUserCtrl.ScannerParams[i], i)) return; } // PLC에서 받은 데이터를 저장 후 다시 로드 Application.Current.Dispatcher.Invoke(() => { RecipeHelper.SaveRecipe(recipe.Name); }); var ChangedRecipe = RecipeHelper.getRecipeInfo(recipe.Name); var diffs = new ObservableCollection(); for (int i = 0; i < 3; i++) { CompareHelper.Fill(RecipeBeforeChanged.ReadOnlyScanParams[i], ChangedRecipe.ReadOnlyScanParams[i], diffs, new CompareHelper.FieldSpec("Draw Speed", x => x.MarkSpeed), new CompareHelper.FieldSpec("Jump Speed", x => x.JumpSpeed), new CompareHelper.FieldSpec("Power#1", x => x.LaserPower1), new CompareHelper.FieldSpec("Power#2", x => x.LaserPower2), new CompareHelper.FieldSpec(nameof(ScannerParam.RampingStartPower), x => x.RampingStartPower), new CompareHelper.FieldSpec(nameof(ScannerParam.RampingStartDist), x => x.RampingStartDist), new CompareHelper.FieldSpec(nameof(ScannerParam.RampingEndPower), x => x.RampingEndPower), new CompareHelper.FieldSpec(nameof(ScannerParam.RampingEndDist), x => x.RampingEndDist) ); if (diffs.Count > 0) { Log.FuncI($"ScanParameter{i + 1} Recipe Changed"); _aurora.RecipeManager.RchHandler().AppendChangedItem(recipe.Name + $"-ScanParam{i + 1}", 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); }); } private bool ApplyReportToParam(ScannerParam param, int parameterNo) { try { // Report -> 모델 (readValue) param.MarkSpeed = getReportData($"{nameof(param.MarkSpeed)}_{parameterNo}").readValue(param.MarkSpeed); param.JumpSpeed = getReportData($"{nameof(param.JumpSpeed)}_{parameterNo}").readValue(param.JumpSpeed); param.LaserPower1 = getReportData($"{nameof(param.LaserPower1)}_{parameterNo}").readValue(param.LaserPower1); param.LaserPower2 = getReportData($"{nameof(param.LaserPower2)}_{parameterNo}").readValue(param.LaserPower2); param.RampingStartPower = getReportData($"{nameof(param.RampingStartPower)}_{parameterNo}").readValue(param.RampingStartPower); param.RampingStartDist = getReportData($"{nameof(param.RampingStartDist)}_{parameterNo}").readValue(param.RampingStartDist); param.RampingEndPower = getReportData($"{nameof(param.RampingEndPower)}_{parameterNo}").readValue(param.RampingEndPower); param.RampingEndDist = getReportData($"{nameof(param.RampingEndDist)}_{parameterNo}").readValue(param.RampingEndDist); return true; } catch (Exception ex) { Log.E($"ApplyReportToParam[{parameterNo}] 예외: {ex.Message}"); MessageUtil.ShowToast($"RMS 파라미터 읽기 중 오류 발생 (param={parameterNo})", Log); _aurora.AlarmService.SetAlarm(AlarmCode.RMS_PAGE_SETTING_NULL); return false; } } private bool ApplyParamToReport(ScannerParam param, int parameterNo) { // 모델 -> Report (Value = ) if (!TrySetReportData($"RecipeNo", _aurora.RecipeManager.ActivatedRecipe().Id)) return false; if (!TrySetReportData($"{nameof(param.MarkSpeed)}_{parameterNo}", param.MarkSpeed)) return false; if (!TrySetReportData($"{nameof(param.JumpSpeed)}_{parameterNo}", param.JumpSpeed)) return false; if (!TrySetReportData($"{nameof(param.LaserPower1)}_{parameterNo}", param.LaserPower1)) return false; if (!TrySetReportData($"{nameof(param.LaserPower2)}_{parameterNo}", param.LaserPower2)) return false; if (!TrySetReportData($"{nameof(param.RampingStartPower)}_{parameterNo}", param.RampingStartPower)) return false; if (!TrySetReportData($"{nameof(param.RampingStartDist)}_{parameterNo}", param.RampingStartDist)) return false; if (!TrySetReportData($"{nameof(param.RampingEndPower)}_{parameterNo}", param.RampingEndPower)) return false; if (!TrySetReportData($"{nameof(param.RampingEndDist)}_{parameterNo}", param.RampingEndDist)) return false; return true; } } }