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

278 lines
18 KiB
C#

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<PropertyDiff>();
CompareHelper.Fill(RecipeBeforeChangedStageA, RecipeStageA, diffs,
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.N2PressMFC), x => x.N2PressMFC),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.AxisZPosition), x => x.AxisZPosition),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.StraightParam.Velocity), x => x.StraightParam.Velocity),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.CurveParam.Velocity), x => x.CurveParam.Velocity),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.StraightParam.CorePowerW), x => x.StraightParam.CorePowerW),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.StraightParam.RingPowerW), x => x.StraightParam.RingPowerW),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.CurveParam.CorePowerW), x => x.CurveParam.CorePowerW),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.RampingOnStartPower), x => x.RampingOnStartPower),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.RampingOnOverlapDist), x => x.RampingOnOverlapDist),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.RampingOffEndPower), x => x.RampingOffEndPower),
new CompareHelper.FieldSpec<MainRecipe>(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<MainRecipe>(nameof(MainRecipe.N2PressMFC), x => x.N2PressMFC),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.AxisZPosition), x => x.AxisZPosition),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.StraightParam.Velocity), x => x.StraightParam.Velocity),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.CurveParam.Velocity), x => x.CurveParam.Velocity),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.StraightParam.CorePowerW), x => x.StraightParam.CorePowerW),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.StraightParam.RingPowerW), x => x.StraightParam.RingPowerW),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.CurveParam.CorePowerW), x => x.CurveParam.CorePowerW),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.RampingOnStartPower), x => x.RampingOnStartPower),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.RampingOnOverlapDist), x => x.RampingOnOverlapDist),
new CompareHelper.FieldSpec<MainRecipe>(nameof(MainRecipe.RampingOffEndPower), x => x.RampingOffEndPower),
new CompareHelper.FieldSpec<MainRecipe>(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);
});
}
}
}