2026-03-30 17:09:29 +09:00

321 lines
12 KiB
C#

using Aurora;
using Aurora.Api;
using Aurora.Api.Manager;
using Aurora.View;
using AuroraLaserScanner;
using CoreUnit.Scanner.UserControl.ScannerCanvas;
using ILSOS_PrismaticScanner.Device;
using ILSOS_PrismaticScanner.Recipes;
using ILSOS_PrismaticScanner.Sequences;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using VisionCommon;
using WeldingCommon;
using WeldingCommon.Alarm;
using WeldingCommon.Data;
using WeldingCommon.Devices;
using WeldingCommon.Popup;
using WeldingCommon.Sequences;
using WeldingCommon.Sequences.Main;
using WeldingCommon.Settings;
using WeldingCommon.Utils;
using WeldingCommon.Views;
using static ILSOS_PrismaticScanner.Device.PLCControllerPrismaticScanner;
using static WeldingCommon.Sequences.Main.SeqExecutePlcBitInterface_InitParam;
using static WeldingCommon.Views.UCCommonAutoRunViewModel;
namespace ILSOS_PrismaticScanner.Views
{
public class UCMainAutoRunViewModel : UCCommonAutoRunViewModel
{
private readonly Logger Log = new Logger("UCMainAutoRunViewModel");
public ICommand CMD_VisibleChanged { get; }
public ICommand CMD_RunSequenceAutoRun { get; }
public ICommand CMD_StopSequenceAutoRun { get; }
public ICommand CMD_Reset { get; } // Totoal Product, Today Product
private readonly IRecipeManager _RecipeManager;
private readonly ISettingEntry _SettingEntry;
private readonly IAlarmService _AlarmService;
private SystemParameter _SystemParameter;
private readonly Scanner _Scanner;
private readonly PLCControllerPrismaticScanner _Plc;
private ISequence _SeqAutoRun;
private ISequence _SeqPlcInterface;
private ISequence _SeqQTest;
public bool IsSequenceRunning_AutoRun { get => _IsSequenceRunning_AutoRun; set => SetProperty(ref _IsSequenceRunning_AutoRun, value); }
private bool _IsSequenceRunning_AutoRun;
public bool IsAlarm { get => _IsAlarm; set => SetProperty(ref _IsAlarm, value); }
private bool _IsAlarm;
private DateTime _NowDateTime;
public DateTime NowDateTime { get => _NowDateTime; set => SetProperty(ref _NowDateTime, value); }
public WeldingData CurrentWeldingData { get => Status.GetProcessingWeldingData(); }
private readonly DispatcherTimer _MonitorTimer;
public UCMainAutoRunViewModel(IAuroraEnvironment aurora, string sequenceId) : base(aurora, sequenceId)
{
_RecipeManager = _Aurora.RecipeManager;
_SettingEntry = _Aurora.SettingEntry;
_AlarmService = _Aurora.AlarmService;
_SystemParameter = _Aurora.SettingEntry[CommonSettingIds.SystemParameter] as SystemParameter;
_Scanner = _Aurora.DeviceManager[CommonDeviceIds.Scanner] as Scanner;
_Plc = _Aurora.DeviceManager[CommonDeviceIds.PLCDevice] as PLCControllerPrismaticScanner;
// MainViewModel에서 RunStateChanged를 설정해준다면, ManualView 상태에서도 해당 이벤트가 호출될지.. 호출될 듯 하긴 함.
_SeqAutoRun = _Aurora.SequenceEntry[SequenceIds.SeqAutoRun];
// Autorun과 Status 변경(Manual, Auto 변경) 시 사용하는 시퀸스ID가 다르도록 설정. 같을 경우, 문제 발생.
_SeqPlcInterface = _Aurora.SequenceEntry[SequenceIds.SeqExecutePlcBitInterfaceForStatusChange];
// Q Test
_SeqQTest = _Aurora.SequenceEntry[SequenceIds.SeqEventQTest];
InitVariable();
CMD_VisibleChanged = new DelegateCommand(VisibleChanged);
CMD_RunSequenceAutoRun = new DelegateCommand(OnAutoRunStartRequest);
CMD_StopSequenceAutoRun = new DelegateCommand(OnStopSequenceAutoRun);
CMD_Reset = new DelegateCommand(PerformCmdReset);
_MonitorTimer = new DispatcherTimer();
_MonitorTimer.Tick += OnMonitoring;
_MonitorTimer.Interval = TimeSpan.FromMilliseconds(100);
_Aurora.EventObservable.AsObservable(CommonEventIds.EVENT_AUTO_RUN_START_REQUEST)
.ObserveOnDispatcher()
.Subscribe(x => OnAutoRunStartRequest());
// Stop이 내려와도 실제 Stop하지 않도록 함
_Aurora.EventObservable.AsObservable(CommonEventIds.EVENT_AUTO_RUN_STOP_REQUEST)
.ObserveOnDispatcher()
.Subscribe(x => new object());
_Aurora.EventObservable.AsObservable(CommonEventIds.EVENT_EQUIPMENT_STATUS_CHANGE)
.Subscribe(x => IsSequenceRunning_AutoRun = Status.EquipmentStatus == eEqpStatus.Auto);
Observable.Merge(
_Aurora.EventObservable.AsObservable(AuroraSysEvent.SYS_ALARM_SET_ALARM),
_Aurora.EventObservable.AsObservable(AuroraSysEvent.SYS_ALARM_RESET_ALARM),
_Aurora.EventObservable.AsObservable(AuroraSysEvent.SYS_ALARM_RESET_ALL_ALARM))
.Subscribe(x => IsAlarm = AlarmManager.HasAlarmLevelHigh());
_Aurora.EventObservable.AsObservable(CommonEventIds.EVENT_CHANGE_RECIPE_INFO)
.ObserveOnDispatcher()
.Select(param => (RecipeInfo)param.Param)
.Subscribe(OnUpdateCurrentActivatedRecipe);
Status.SetWorkingPosition(eWorkingPosition.NONE);
}
private void InitVariable()
{
NowDateTime = DateTime.Now;
if (NowDateTime.Day != _SystemParameter.LastProductTime.Day)
InitializeTodayCount();
CurrentWeldingData.TodayProduct = _SystemParameter.TodayProductCount;
CurrentWeldingData.TotalProduct = _SystemParameter.TotalProductCount;
CurrentWeldingData.AutoRunStartTime = default(DateTime);
CurrentWeldingData.WeldingEndTime = _SystemParameter.LastProductTime;
CurrentWeldingData.WeldingSpanTimeMilliseconds = "0";
CurrentWeldingData.LotId = "Default_Lot_Id";
CurrentWeldingData.CellId = "Default_Cell_Id";
}
private void OnUpdateCurrentActivatedRecipe(RecipeInfo info)
{
// Activate Layer 불러오기
RecipeHelper.OnActiveReloaded();
// Page UI 업데이트
RecipeHelper.UpdateAutorunRecipe();
}
private void VisibleChanged(object obj)
{
bool visible = (bool)obj;
if (visible) {
_MonitorTimer.Start();
} else {
_MonitorTimer.Stop();
}
}
private void OnMonitoring(object sender, EventArgs e)
{
// 켜져있는 상태에서는 24시 넘어갈 때만 초기화
if (NowDateTime.Day != DateTime.Now.Day)
InitializeTodayCount();
NowDateTime = DateTime.Now;
}
// PLC 비트에 의한 AutoRun 실행의 경우, PLC 인터페이스 이후 AutoRun 필요
public override async void OnAutoRunStartRequest(object obj = null)
{
if (!ApproveAutorunByUserOrAuto()) { return; }
base.OnAutoRunStartRequest();
//// PLC_AUTO_REQ 신호가 점멸로 오기 때문에.. 일단 auto로 살림
//_Plc.WriteBit(eBitOutput.PC_AUTO_STATUS, true);
bool IsStart = await TimerMessageBox.ShowAsync(Application.Current.MainWindow, "운전 시작", "자동 운전을 시작하시겠습니까?", true, 5000);
if (!IsStart) {
return;
}
// PLC에선 Auto Req 받으면 바로 살려주도록
Status.GetProcessingWeldingData().AutoRunStartTime = DateTime.Now;
RunSequenceAutoRun();
}
private void RunSequenceAutoRun()
{
// 자동으로 Activated Recipe로 변경
OnUpdateCurrentActivatedRecipe(null);
var param = new SeqAutoRunPrismaticScanner_InitParam() {
VisionRecipeNo = 0
};
Status.SetStatus(eEqpStatus.Auto);
_SeqAutoRun.Start(param, OnCompleteAutoRun);
}
private void OnCompleteAutoRun(SequenceActionResult res)
{
if (res != null) {
if (res.Param is SeqAutoRunPrismaticScanner_OutParam result && result.Success == true) {
MessageUtil.ShowSuccessToast(string.Format("Success SeqAutoRunPrismaticScanner"));
return;
}
}
MessageUtil.ShowWarningToast(string.Format("Fail SeqAutoRunPrismaticScanner"));
}
private bool ApproveAutorunByUserOrAuto()
{
bool boolian = AlarmManager.HasAlarmLevelHigh();
if (boolian) {
Log.E($"Clear Heavy Alarms For Welding!");
MessageUtil.ShowWarningToast(string.Format("Clear Heavy Alarms For Welding!"));
return false;
}
boolian = AlarmManager.IsPlcDoorOpen();
if (boolian) {
Log.E($"PLC Door Opened!! Can't Weld Now.");
MessageUtil.ShowWarningToast(string.Format("Close Door ! Clear PLC DoorInterlock!"));
return false;
}
boolian = AlarmManager.IsPlcEmoAlarm();
if (boolian) {
Log.E($"PLC EMO Pushed!! Can't Weld Now.");
MessageUtil.ShowWarningToast(string.Format("Clear PLC EMO Status!"));
return false;
}
if (VisionRecipeManager.GetFovInfos().Count == 0) {
MessageUtil.ShowWarningToast(string.Format("Please check the Vision Recipe of the currently active Recipe."));
return false;
}
if (_SeqAutoRun.RunState == SequenceRunState.Running) {
MessageUtil.ShowWarningToast(string.Format("이미 시퀀스가 Start 상태입니다.", "SeqAutoRunPrismaticScanner"), Log);
return false;
}
return true;
}
public override void OnAutoRunStopRequest()
{
base.OnAutoRunStopRequest();
//// Prewelding은 자동 운전 정지 와도 무시
//StopSequenceAutoRun();
}
private void OnStopSequenceAutoRun(object obj = null)
{
if (_SeqAutoRun.RunState == SequenceRunState.Idle) {
return;
}
_SeqAutoRun.Stop();
//Recipe를 기존에 선택된 Recipe로 Rollback 해 줌
RecipeHelper.RollbackRecipe();
//AutoRun 정지 시 CorrectionFile을 Vision으로 변경
_Scanner.SelectCorrectionTable(1);
}
private void PerformCmdReset(object commandParameter)
{
// SystemParameter를 저장하기 전에는 반드시 업데이트를 해주어야 한다.
_SystemParameter = _Aurora.SettingEntry[CommonSettingIds.SystemParameter] as SystemParameter;
switch ((string)commandParameter) {
case "TotalProduct": {
CurrentWeldingData.TotalProduct = 0;
_SystemParameter.TotalProductCount = CurrentWeldingData.TotalProduct;
Status.GetProcessingWeldingData().TotalProduct = 0;
_SettingEntry.Save(CommonSettingIds.SystemParameter, _SystemParameter, "UCMainAutoRunViewModel");
}
break;
case "TodayProduct": {
CurrentWeldingData.TodayProduct = 0;
_SystemParameter.TodayProductCount = CurrentWeldingData.TodayProduct;
Status.GetProcessingWeldingData().TodayProduct = 0;
_SettingEntry.Save(CommonSettingIds.SystemParameter, _SystemParameter, "UCMainAutoRunViewModel");
}
break;
default:
return;
}
}
private void InitializeTodayCount()
{
// SystemParameter를 저장하기 전에는 반드시 업데이트를 해주어야 한다.
// SystemParameter에 저장된 값 불러오기
_SystemParameter = _Aurora.SettingEntry[CommonSettingIds.SystemParameter] as SystemParameter;
CurrentWeldingData.TodayProduct = 0;
_SystemParameter.TodayProductCount = CurrentWeldingData.TodayProduct;
_SettingEntry.Save(CommonSettingIds.SystemParameter, _SystemParameter, "UCMainAutoRunViewModel");
}
}
enum InputType
{
keyboardInput,
ClickInput
}
}