2026-06-05 13:44:39 +09:00

225 lines
11 KiB
C#

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.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 < 4; 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 < 4; 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<PropertyDiff>();
for (int i = 0; i < 4; i++) {
CompareHelper.Fill(RecipeBeforeChanged.ReadOnlyScanParams[i], ChangedRecipe.ReadOnlyScanParams[i], diffs,
new CompareHelper.FieldSpec<ScannerParam>("Draw Speed", x => x.MarkSpeed),
new CompareHelper.FieldSpec<ScannerParam>("Jump Speed", x => x.JumpSpeed),
new CompareHelper.FieldSpec<ScannerParam>("Power#1", x => x.LaserPower1),
new CompareHelper.FieldSpec<ScannerParam>("Power#2", x => x.LaserPower2),
new CompareHelper.FieldSpec<ScannerParam>(nameof(ScannerParam.RampingStartPower), x => x.RampingStartPower),
new CompareHelper.FieldSpec<ScannerParam>(nameof(ScannerParam.RampingStartDist), x => x.RampingStartDist),
new CompareHelper.FieldSpec<ScannerParam>(nameof(ScannerParam.RampingEndPower), x => x.RampingEndPower),
new CompareHelper.FieldSpec<ScannerParam>(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를 통해서 써주기까지 함
/// <Method 참조 cref="WeldingCommon.Views.UCScannerObjectTeachingViewModel.OnActivatedRecipe"/>
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;
}
}
}