1142 lines
36 KiB
C#
1142 lines
36 KiB
C#
using Aitex.Core.Util;
|
|
using Aitex.Sorter.Common;
|
|
using MECF.Framework.Common.CommonData;
|
|
using MECF.Framework.Common.DataCenter;
|
|
using MECF.Framework.Common.OperationCenter;
|
|
using MECF.Framework.Common.RecipeCenter;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
using System.Windows;
|
|
using Caliburn.Micro;
|
|
using MECF.Framework.UI.Client.CenterViews.Editors.Sequence;
|
|
using MECF.Framework.UI.Client.CenterViews.Operations.WaferAssociation;
|
|
using MECF.Framework.UI.Client.ClientBase;
|
|
using OpenSEMI.ClientBase;
|
|
using System;
|
|
using SicUI.Controls;
|
|
using System.Data;
|
|
using Aitex.Core.RT.Event;
|
|
using System.Dynamic;
|
|
using Caliburn.Micro.Core;
|
|
|
|
namespace SicUI.Models.Operations.Overviews
|
|
{
|
|
public class JobListInfo : NotifiableItem
|
|
{
|
|
public int Index { get; set; }
|
|
public string WaferID { get; set; }
|
|
public string LotName { get; set; }
|
|
|
|
private string _status;
|
|
public string Status
|
|
{
|
|
get { return _status; }
|
|
set
|
|
{
|
|
_status = value;
|
|
InvokePropertyChanged();
|
|
}
|
|
}
|
|
|
|
private string _currentPosition;
|
|
public string CurrentPosition
|
|
{
|
|
get { return _currentPosition; }
|
|
set
|
|
{
|
|
_currentPosition = value;
|
|
InvokePropertyChanged();
|
|
}
|
|
}
|
|
public string CreateTime { get; set; }
|
|
public string RecipeName { get; set; }
|
|
}
|
|
|
|
public class OverViewViewModel : SicUIViewModelBase, IHandle<ShowCloseMonitorWinEvent>
|
|
{
|
|
private R_TRIG _manulAbort = new R_TRIG();
|
|
private R_TRIG _loadLockJobDone = new R_TRIG();
|
|
private R_TRIG _moduleOffLineTimeout = new R_TRIG();
|
|
private int _scModuleOfflineTimeout = 60;
|
|
private int _offlineTimes = 0;
|
|
private bool _systemAbort = false;
|
|
|
|
#region Property
|
|
public ObservableCollection<JobListInfo> JobListInfoData { get; set; }
|
|
|
|
public WaferAssociationInfo LoadWaferAssociation { get; set; }
|
|
|
|
public bool IsPM1Installed { get; set; }
|
|
public bool IsPM2Installed { get; set; }
|
|
public bool IsBufferInstalled { get; set; }
|
|
public bool IsLoadLockInstalled { get; set; }
|
|
public bool IsUnLoadInstalled { get; set; }
|
|
public bool IsTMInstalled { get; set; }
|
|
|
|
#region Mainframe
|
|
[Subscription("LoadLock.JobDone")]
|
|
public bool LoadLockJobDone { get; set; }
|
|
|
|
[Subscription("TMRobot.RobotMoveInfo")]
|
|
public RobotMoveInfo TmRobotMoveInfo
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public FoupDoorState PM1DoorState
|
|
{
|
|
get
|
|
{
|
|
if (PM1SlitValveOpenFeedback && !PM1SlitValveCloseFeedback) return FoupDoorState.Open;
|
|
if (!PM1SlitValveOpenFeedback && PM1SlitValveCloseFeedback) return FoupDoorState.Close;
|
|
|
|
return FoupDoorState.Unknown;
|
|
}
|
|
}
|
|
|
|
public FoupDoorState PM2DoorState
|
|
{
|
|
get
|
|
{
|
|
if (PM2SlitValveOpenFeedback && !PM2SlitValveCloseFeedback) return FoupDoorState.Open;
|
|
if (!PM2SlitValveOpenFeedback && PM2SlitValveCloseFeedback) return FoupDoorState.Close;
|
|
|
|
return FoupDoorState.Unknown;
|
|
}
|
|
}
|
|
|
|
public FoupDoorState LLDoorState
|
|
{
|
|
get
|
|
{
|
|
if (LLDoorOpenFeedback && !LLDoorCloseFeedback) return FoupDoorState.Open;
|
|
if (!LLDoorOpenFeedback && LLDoorCloseFeedback) return FoupDoorState.Close;
|
|
|
|
return FoupDoorState.Unknown;
|
|
}
|
|
}
|
|
|
|
public FoupDoorState BufferDoorState
|
|
{
|
|
get
|
|
{
|
|
{
|
|
if (BufferDoorOpenFeedback && !BufferDoorCloseFeedback) return FoupDoorState.Open;
|
|
if (!BufferDoorOpenFeedback && BufferDoorCloseFeedback) return FoupDoorState.Close;
|
|
}
|
|
|
|
return FoupDoorState.Unknown;
|
|
}
|
|
}
|
|
|
|
public bool IsLLDoorOpen => LLDoorState == FoupDoorState.Open ? true : false;
|
|
public bool IsBufferDoorOpen => true;
|
|
public bool IsPM1DoorOpen => PM1DoorState == FoupDoorState.Open ? true : false;
|
|
public bool IsPM2DoorOpen => PM2DoorState == FoupDoorState.Open ? true : false;
|
|
|
|
public Visibility IsPM1Water
|
|
{
|
|
get
|
|
{
|
|
if (PM1Wafer != null && JobListInfoData != null)
|
|
{
|
|
for (int i = 0; i < JobListInfoData.Count; i++)
|
|
{
|
|
if (JobListInfoData[i].WaferID == PM1Wafer.WaferID)
|
|
{
|
|
JobListInfoData[i].Status = GetWaferStatue(PM1Wafer.WaferStatus);
|
|
JobListInfoData[i].CurrentPosition = "PM1";
|
|
}
|
|
}
|
|
}
|
|
return PM1Wafer == null ? Visibility.Hidden : PM1Wafer.IsVisibility;
|
|
}
|
|
}
|
|
public Visibility IsPM2Water
|
|
{
|
|
get
|
|
{
|
|
if (PM2Wafer != null && JobListInfoData != null)
|
|
{
|
|
for (int i = 0; i < JobListInfoData.Count; i++)
|
|
{
|
|
if (JobListInfoData[i].WaferID == PM2Wafer.WaferID)
|
|
{
|
|
JobListInfoData[i].Status = GetWaferStatue(PM2Wafer.WaferStatus);
|
|
JobListInfoData[i].CurrentPosition = "PM2";
|
|
}
|
|
}
|
|
}
|
|
return PM2Wafer == null ? Visibility.Hidden : PM2Wafer.IsVisibility;
|
|
}
|
|
}
|
|
|
|
public Visibility IsLLWater
|
|
{
|
|
get
|
|
{
|
|
if (LoadLockWafer != null && JobListInfoData != null)
|
|
{
|
|
for (int i = 0; i < JobListInfoData.Count; i++)
|
|
{
|
|
if (JobListInfoData[i].WaferID == LoadLockWafer.WaferID)
|
|
{
|
|
JobListInfoData[i].Status = GetWaferStatue(LoadLockWafer.WaferStatus);
|
|
JobListInfoData[i].CurrentPosition = "LoadLock";
|
|
}
|
|
}
|
|
}
|
|
return LoadLockWafer == null ? Visibility.Hidden : LoadLockWafer.IsVisibility;
|
|
}
|
|
}
|
|
|
|
public Visibility IsBufferWater
|
|
{
|
|
get
|
|
{
|
|
if (BufferWafer != null && JobListInfoData != null)
|
|
{
|
|
for (int i = 0; i < JobListInfoData.Count; i++)
|
|
{
|
|
if (JobListInfoData[i].WaferID == BufferWafer.WaferID)
|
|
{
|
|
JobListInfoData[i].Status = GetWaferStatue(BufferWafer.WaferStatus);
|
|
JobListInfoData[i].CurrentPosition = "Buffer";
|
|
}
|
|
}
|
|
}
|
|
return BufferWafer == null ? Visibility.Hidden : BufferWafer.IsVisibility;
|
|
}
|
|
}
|
|
|
|
public Visibility IsArmWater
|
|
{
|
|
get
|
|
{
|
|
if (TMRobotWafer1 != null && JobListInfoData != null)
|
|
{
|
|
for (int i = 0; i < JobListInfoData.Count; i++)
|
|
{
|
|
if (JobListInfoData[i].WaferID == TMRobotWafer1.WaferID)
|
|
{
|
|
//JobListInfoData[i].Status = MECF.Framework.Common.SubstrateTrackings.WaferManager.Instance.AllLocationWafers[MECF.Framework.Common.Equipment.ModuleName.TMRobot][0].ProcessState.ToString();
|
|
JobListInfoData[i].CurrentPosition = "TM";
|
|
}
|
|
}
|
|
}
|
|
return TMRobotWafer1 == null ? Visibility.Hidden : TMRobotWafer1.IsVisibility;
|
|
}
|
|
}
|
|
public Visibility IsUnloadWater
|
|
{
|
|
get
|
|
{
|
|
if (UnLoadWafer != null && JobListInfoData != null)
|
|
{
|
|
for (int i = 0; i < JobListInfoData.Count; i++)
|
|
{
|
|
if (JobListInfoData[i].WaferID == UnLoadWafer.WaferID)
|
|
{
|
|
JobListInfoData[i].CurrentPosition = "Unload";
|
|
}
|
|
}
|
|
}
|
|
return UnLoadWafer == null ? Visibility.Hidden : UnLoadWafer.IsVisibility;
|
|
}
|
|
}
|
|
|
|
private string GetWaferStatue(int status)
|
|
{
|
|
if (status == 3)
|
|
{
|
|
return "InProcess";
|
|
}
|
|
else if (status == 7 || status == 4)
|
|
{
|
|
return "Completed";
|
|
}
|
|
else if (status == 3)
|
|
{
|
|
return "Wait";
|
|
}
|
|
else if (status == 5)
|
|
{
|
|
return "Failed";
|
|
}
|
|
else
|
|
{
|
|
return "Idle";
|
|
}
|
|
}
|
|
|
|
[Subscription("TM.PM1Door.OpenFeedback")]
|
|
public bool PM1SlitValveOpenFeedback { get; set; }
|
|
|
|
[Subscription("TM.PM1Door.CloseFeedback")]
|
|
public bool PM1SlitValveCloseFeedback { get; set; }
|
|
|
|
[Subscription("TM.PM2Door.OpenFeedback")]
|
|
public bool PM2SlitValveOpenFeedback { get; set; }
|
|
|
|
[Subscription("TM.PM2Door.CloseFeedback")]
|
|
public bool PM2SlitValveCloseFeedback { get; set; }
|
|
|
|
[Subscription("TM.BufferDoor.OpenFeedback")]
|
|
public bool BufferDoorOpenFeedback { get; set; }
|
|
|
|
[Subscription("TM.BufferDoor.CloseFeedback")]
|
|
public bool BufferDoorCloseFeedback { get; set; }
|
|
|
|
[Subscription("TM.LoadLockDoor.OpenFeedback")]
|
|
public bool LLDoorOpenFeedback { get; set; }
|
|
|
|
[Subscription("TM.LoadLockDoor.CloseFeedback")]
|
|
public bool LLDoorCloseFeedback { get; set; }
|
|
|
|
|
|
[Subscription("TM.TMPressure.Value")]
|
|
public float TMPressure { get; set; }
|
|
|
|
[Subscription("TM.LLPressure.Value")]
|
|
public double LLPressure { get; set; }
|
|
|
|
[Subscription("Buffer.BufferTemp.FeedBack")]
|
|
public float BufferTemp { get; set; }
|
|
|
|
[Subscription("LL.LLTemp.FeedBack")]
|
|
public float LLTemp { get; set; }
|
|
|
|
[Subscription("LoadLock.LLLidClosed.Value")]
|
|
public bool LLLidClosed { get; set; }
|
|
|
|
[Subscription("TM.UnLoadPressure.Value")]
|
|
public double UnLoadPressure { get; set; }
|
|
|
|
//public bool IsEnableJobLP1
|
|
//{
|
|
// get { return IsAuto; }
|
|
//}
|
|
|
|
public bool IsEnableJobLP1
|
|
{
|
|
get { return true; }
|
|
}
|
|
#endregion
|
|
|
|
#region PM1
|
|
|
|
[Subscription("PM1.Status")]
|
|
public string PM1Status { get; set; }
|
|
public string PM1StatusBackground
|
|
{
|
|
get { return ModuleStatusBackground.GetStatusBackground(PM1Status); }
|
|
}
|
|
|
|
public string PM1SelectedRecipe { get; set; }
|
|
private string PM1SelectedRecipePath { get; set; }
|
|
|
|
|
|
[Subscription("PM1.RecipeTotalElapseTime")]
|
|
public int PM1RecipeTotalElapseTime { get; set; }
|
|
|
|
public string ElapseTimePM1 => PM1Wafer != null && PM1Wafer.WaferStatus == 3 ? PM1RecipeTotalElapseTime.ToString() : "--";
|
|
|
|
[Subscription("PM1.RecipeTotalTime")]
|
|
public int PM1RecipeTotalTime { get; set; }
|
|
public string TotalTimePM1 => PM1Wafer != null && PM1Wafer.WaferStatus == 3 ? PM1RecipeTotalTime.ToString() : "--";
|
|
|
|
[Subscription("PM1.PT1.FeedBack")]
|
|
public double PM1Pressure { get; set; }
|
|
|
|
|
|
[Subscription("PM1.IsOnline")]
|
|
public bool PM1IsOnline { get; set; }
|
|
|
|
public bool PM1IsOffline
|
|
{
|
|
get { return !PM1IsOnline; }
|
|
}
|
|
|
|
[Subscription("TM.IsOnline")]
|
|
public bool TMIsOnline { get; set; }
|
|
|
|
[Subscription("Buffer.IsOnline")]
|
|
public bool BufferIsOnline { get; set; }
|
|
|
|
[Subscription("LoadLock.IsOnline")]
|
|
public bool LoadLockIsOnline { get; set; }
|
|
|
|
|
|
[Subscription("PM1.ConfinementRing.RingUpSensor")]
|
|
public bool PM1ConfinementRingUpSensor { get; set; }
|
|
|
|
[Subscription("PM1.ConfinementRing.RingDownSensor")]
|
|
public bool PM1ConfinementRingDwonSensor { get; set; }
|
|
|
|
public string PM1ConfinementState
|
|
{
|
|
get
|
|
{
|
|
if (PM1ConfinementRingUpSensor && !PM1ConfinementRingDwonSensor)
|
|
{
|
|
return "Up";
|
|
}
|
|
else if (!PM1ConfinementRingUpSensor && PM1ConfinementRingDwonSensor)
|
|
{
|
|
return "Down";
|
|
}
|
|
else
|
|
{
|
|
return "Unknown";
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region PM2
|
|
|
|
[Subscription("PM2.Status")]
|
|
public string PM2Status { get; set; }
|
|
public string PM2StatusBackground
|
|
{
|
|
get { return ModuleStatusBackground.GetStatusBackground(PM2Status); }
|
|
}
|
|
|
|
public string PM2SelectedRecipe { get; set; }
|
|
private string PM2SelectedRecipePath { get; set; }
|
|
|
|
|
|
[Subscription("PM2.RecipeTotalElapseTime")]
|
|
public int PM2RecipeTotalElapseTime { get; set; }
|
|
|
|
public string ElapseTimePM2 => PM2Wafer != null && PM2Wafer.WaferStatus == 3 ? PM2RecipeTotalElapseTime.ToString() : "--";
|
|
|
|
[Subscription("PM2.RecipeTotalTime")]
|
|
public int PM2RecipeTotalTime { get; set; }
|
|
public string TotalTimePM2 => PM2Wafer != null && PM2Wafer.WaferStatus == 3 ? PM2RecipeTotalTime.ToString() : "--";
|
|
|
|
[Subscription("PM2.PT1.FeedBack")]
|
|
public double PM2Pressure { get; set; }
|
|
|
|
|
|
[Subscription("PM2.IsOnline")]
|
|
public bool PM2IsOnline { get; set; }
|
|
|
|
public bool PM2IsOffline
|
|
{
|
|
get { return !PM2IsOnline; }
|
|
}
|
|
|
|
[Subscription("PM2.ConfinementRing.RingUpSensor")]
|
|
public bool PM2ConfinementRingUpSensor { get; set; }
|
|
|
|
[Subscription("PM2.ConfinementRing.RingDownSensor")]
|
|
public bool PM2ConfinementRingDwonSensor { get; set; }
|
|
|
|
public string PM2ConfinementState
|
|
{
|
|
get
|
|
{
|
|
if (PM2ConfinementRingUpSensor && !PM2ConfinementRingDwonSensor)
|
|
{
|
|
return "Up";
|
|
}
|
|
else if (!PM2ConfinementRingUpSensor && PM2ConfinementRingDwonSensor)
|
|
{
|
|
return "Down";
|
|
}
|
|
else
|
|
{
|
|
return "Unknown";
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Scheduler
|
|
|
|
public bool IsRtInitialized
|
|
{
|
|
get
|
|
{
|
|
return RtStatus != "Init" && RtStatus != "Initializing";
|
|
}
|
|
}
|
|
|
|
public bool IsRtRunning
|
|
{
|
|
get
|
|
{
|
|
return RtStatus != "Init" && RtStatus != "Idle";
|
|
}
|
|
}
|
|
|
|
public bool IsAuto
|
|
{
|
|
get { return RtStatus == "AutoRunning" || RtStatus == "AutoIdle"; }
|
|
}
|
|
|
|
public string RunningMode => IsAuto ? "Auto" : "Manual";
|
|
|
|
[Subscription("Rt.Status")]
|
|
public string RtStatus { get; set; }
|
|
|
|
[Subscription("Scheduler.IsCycleMode")]
|
|
public bool IsCycleMode { get; set; }
|
|
|
|
[Subscription("Scheduler.CycledCount")]
|
|
public int CycledCount { get; set; } //当前次数
|
|
|
|
public int CurrentCycle
|
|
{
|
|
get
|
|
{
|
|
if (CycleSetPoint <= 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (CycledCount + 1 > CycleSetPoint)
|
|
{
|
|
return CycleSetPoint;
|
|
}
|
|
else
|
|
{
|
|
return CycledCount + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
[Subscription("Scheduler.CycleSetPoint")]
|
|
public int CycleSetPoint { get; set; } //总次数
|
|
|
|
[Subscription("LoadLock.LocalJobName")]
|
|
public string LoadLockJobName { get; set; }
|
|
|
|
[Subscription("LoadLock.LocalJobStatus")]
|
|
public string LoadLockJobStatus { get; set; }
|
|
#endregion
|
|
|
|
#region Buffer
|
|
[Subscription("Scheduler.TimeBuffer1")]
|
|
public double TimeBuffer1 { get; set; }
|
|
|
|
[Subscription("Scheduler.TimeBuffer2")]
|
|
public double TimeBuffer2 { get; set; }
|
|
|
|
[Subscription("Scheduler.TimeBuffer3")]
|
|
public double TimeBuffer3 { get; set; }
|
|
|
|
[Subscription("LoadLock.IsOnline")]
|
|
public bool LoadIsOnline { get; set; }
|
|
|
|
[Subscription("UnLoad.IsOnline")]
|
|
public bool UnLoadIsOnline { get; set; }
|
|
|
|
#endregion
|
|
|
|
#region Button Logic
|
|
|
|
|
|
|
|
public bool PM1EnableWaferClick => !PM1IsOnline || RtStatus == "Idle";
|
|
|
|
public bool PM2EnableWaferClick => !PM2IsOnline || RtStatus == "Idle";
|
|
|
|
public bool LLEnableWaferClick => !LoadIsOnline || RtStatus == "Idle";
|
|
|
|
public bool UnLoadEnableWaferClick => !UnLoadIsOnline || RtStatus == "Idle";
|
|
|
|
public bool BufferEnableWaferClick => !BufferIsOnline || RtStatus == "Idle";
|
|
|
|
public bool TMEnableWaferClick => !TMIsOnline || RtStatus == "Idle";
|
|
|
|
public bool EnableWaferClick => RtStatus == "Idle";
|
|
|
|
|
|
public bool IsEnableAbort
|
|
{
|
|
get
|
|
{
|
|
if (IsAuto)
|
|
return !string.IsNullOrEmpty(LoadLockJobStatus);
|
|
|
|
return IsRtRunning;
|
|
}
|
|
}
|
|
|
|
public bool IsEnableAuto
|
|
{
|
|
get { return !IsAuto && IsRtInitialized; }
|
|
}
|
|
|
|
public bool IsEnableManual
|
|
{
|
|
get { return IsAuto && IsRtInitialized && string.IsNullOrEmpty(LoadLockJobStatus); }
|
|
}
|
|
|
|
public bool IsEnableInitialize
|
|
{
|
|
get { return !IsAuto && !IsRtRunning; }
|
|
}
|
|
|
|
|
|
public bool IsEnableReturnAll
|
|
{
|
|
get { return !IsAuto && IsRtInitialized && RtStatus == "Idle"; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
public OverViewViewModel()
|
|
{
|
|
this.DisplayName = "OverViewViewModel";
|
|
ActiveUpdateData = true;
|
|
}
|
|
|
|
protected override void OnInitialize()
|
|
{
|
|
base.OnInitialize();
|
|
|
|
InitLL();
|
|
InitTM();
|
|
InitPM();
|
|
|
|
LoadWaferAssociation = new WaferAssociationInfo();
|
|
LoadWaferAssociation.ModuleData = ModuleManager.ModuleInfos["LoadLock"];
|
|
|
|
IsPM1Installed = (bool)QueryDataClient.Instance.Service.GetConfig("System.SetUp.IsPM1Installed");
|
|
IsPM2Installed = (bool)QueryDataClient.Instance.Service.GetConfig("System.SetUp.IsPM2Installed");
|
|
IsBufferInstalled = (bool)QueryDataClient.Instance.Service.GetConfig("System.SetUp.IsBufferInstalled");
|
|
IsLoadLockInstalled = (bool)QueryDataClient.Instance.Service.GetConfig("System.SetUp.IsLoadLockInstalled");
|
|
IsTMInstalled = (bool)QueryDataClient.Instance.Service.GetConfig("System.SetUp.IsTMInstalled");
|
|
//IsUnLoadInstalled = (bool)QueryDataClient.Instance.Service.GetConfig("System.SetUp.IsUnLoadInstalled");
|
|
IsUnLoadInstalled = true;
|
|
}
|
|
public Visibility ProcessMonitorButtonVisibility { get; private set; }
|
|
protected override void OnActivate()
|
|
{
|
|
var roleID = BaseApp.Instance.UserContext.RoleID;
|
|
var allowProcessMonitorWin = RoleAccountProvider.Instance.GetMenuPermission(roleID, "PM1.Process.ProcessMonitorWindow") != (int)MenuPermissionEnum.MP_NONE;
|
|
ProcessMonitorButtonVisibility = allowProcessMonitorWin ? Visibility.Visible : Visibility.Collapsed;
|
|
|
|
base.OnActivate();
|
|
}
|
|
|
|
protected override void Poll()
|
|
{
|
|
base.Poll();
|
|
PM1SelectedRecipePath = (string)QueryDataClient.Instance.Service.GetConfig($"PM.PM1.LastRecipeName");
|
|
PM2SelectedRecipePath = (string)QueryDataClient.Instance.Service.GetConfig($"PM.PM2.LastRecipeName");
|
|
|
|
if (!string.IsNullOrEmpty(PM1SelectedRecipePath))
|
|
{
|
|
var array = PM1SelectedRecipePath.Split(new char[] { '\\' });
|
|
|
|
if (PM1SelectedRecipe != array[array.Length - 1])
|
|
{
|
|
PM1SelectedRecipe = array[array.Length - 1];
|
|
}
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(PM2SelectedRecipePath))
|
|
{
|
|
var array = PM2SelectedRecipePath.Split(new char[] { '\\' });
|
|
|
|
if (PM2SelectedRecipe != array[array.Length - 1])
|
|
{
|
|
PM2SelectedRecipe = array[array.Length - 1];
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ReturnAllWafer()
|
|
{
|
|
InvokeClient.Instance.Service.DoOperation("System.ReturnAllWafer");
|
|
}
|
|
|
|
protected override void InvokeAfterUpdateProperty(Dictionary<string, object> data)
|
|
{
|
|
if (LoadWaferAssociation == null)
|
|
{
|
|
LoadWaferAssociation = new WaferAssociationInfo();
|
|
LoadWaferAssociation.ModuleData = ModuleManager.ModuleInfos["LoadLock"];
|
|
}
|
|
|
|
LoadWaferAssociation.JobID = LoadLockJobName;
|
|
LoadWaferAssociation.JobStatus = LoadLockJobStatus;
|
|
|
|
GetJobList();
|
|
|
|
_loadLockJobDone.CLK = LoadLockJobDone && (!IsCycleMode || (IsCycleMode && CycledCount >= CycleSetPoint));
|
|
if (_loadLockJobDone.Q)
|
|
{
|
|
EV.PostInfoLog("System", "Process completed.Please take away the wafer.");
|
|
|
|
//Buzzer,报警次数,每次间隔,每次持续时间
|
|
SwitchOffBuzzerEx("3", "1500", "2000");
|
|
}
|
|
|
|
_manulAbort.CLK = _systemAbort;
|
|
if (_manulAbort.Q)
|
|
{
|
|
EV.PostWarningLog("System", "Process aborted.Please take away the wafer.");
|
|
_systemAbort = false;
|
|
}
|
|
|
|
if (RtStatus == "AutoRunning")
|
|
{
|
|
if (!TMIsOnline || !BufferIsOnline || !LoadLockIsOnline)
|
|
{
|
|
_offlineTimes++;
|
|
}
|
|
else
|
|
{
|
|
_offlineTimes = 0;
|
|
}
|
|
|
|
_moduleOffLineTimeout.CLK = _offlineTimes > _scModuleOfflineTimeout && _offlineTimes < _scModuleOfflineTimeout + 5;
|
|
if (_moduleOffLineTimeout.Q)
|
|
{
|
|
EV.PostWarningLog("System", $"Module is in offline status over {_scModuleOfflineTimeout} seconds.");
|
|
}
|
|
}
|
|
}
|
|
|
|
#region OverView Operation
|
|
|
|
public void HomeAll()
|
|
{
|
|
InvokeClient.Instance.Service.DoOperation("System.HomeAll");
|
|
}
|
|
|
|
public void Abort()
|
|
{
|
|
if (RtStatus == "AutoRunning")
|
|
{
|
|
_systemAbort = true;
|
|
}
|
|
InvokeClient.Instance.Service.DoOperation("System.Abort");
|
|
}
|
|
|
|
public void Auto()
|
|
{
|
|
ChooseDialogBoxViewModel dialog = new ChooseDialogBoxViewModel();
|
|
dialog.DisplayName = "Tips";
|
|
dialog.InfoStr = "Please Check All Gas Ready Before Start Process!";
|
|
|
|
WindowManager wm = new WindowManager();
|
|
bool? bret = wm.ShowDialog(dialog);
|
|
if (!bret.HasValue || !bret.Value)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//传入SequenceName
|
|
InvokeClient.Instance.Service.DoOperation("System.SetAutoMode");
|
|
|
|
JobListInfoData = new ObservableCollection<JobListInfo>();
|
|
}
|
|
|
|
public void Manual()
|
|
{
|
|
InvokeClient.Instance.Service.DoOperation("System.SetManualMode");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Wafer association
|
|
#region Sequence operation
|
|
public void SelectSequence(WaferAssociationInfo info)
|
|
{
|
|
SequenceDialogViewModel dialog = new SequenceDialogViewModel();
|
|
dialog.DisplayName = "Select Sequence";
|
|
|
|
dialog.Files = new ObservableCollection<FileNode>(RecipeSequenceTreeBuilder.GetFiles("",
|
|
RecipeClient.Instance.Service.GetSequenceNameList()
|
|
));
|
|
|
|
WindowManager wm = new WindowManager();
|
|
bool? bret = wm.ShowDialog(dialog);
|
|
if ((bool)bret)
|
|
{
|
|
info.SequenceName = dialog.DialogResult;
|
|
}
|
|
}
|
|
|
|
public void SetSlot(WaferAssociationInfo info)
|
|
{
|
|
if (InputSlotCheck(info.SlotFrom, info.SlotTo))
|
|
AssociateSequence(info, true);
|
|
}
|
|
|
|
public void SkipSlot(WaferAssociationInfo info)
|
|
{
|
|
if (InputSlotCheck(info.SlotFrom, info.SlotTo))
|
|
AssociateSequence(info, false);
|
|
}
|
|
|
|
public void SetAll(WaferAssociationInfo info)
|
|
{
|
|
info.SlotFrom = 1;
|
|
info.SlotTo = 25;
|
|
AssociateSequence(info, true);
|
|
}
|
|
|
|
public void DeselectAll(WaferAssociationInfo info)
|
|
{
|
|
info.SlotFrom = 1;
|
|
info.SlotTo = 25;
|
|
AssociateSequence(info, false);
|
|
}
|
|
|
|
public void SetSequence(WaferAssociationInfo info, int slotIndex, string seqName)
|
|
{
|
|
bool flag = string.IsNullOrEmpty(seqName);
|
|
AssociateSequence(info, flag, slotIndex - 1);
|
|
}
|
|
|
|
private bool InputSlotCheck(int from, int to)
|
|
{
|
|
if (from > to)
|
|
{
|
|
DialogBox.ShowInfo("This index of from slot should be large than the index of to slot.");
|
|
return false;
|
|
}
|
|
if (from < 1 || to > 25)
|
|
{
|
|
DialogBox.ShowInfo("This input value for from should be between 1 and 25.");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void AssociateSequence(WaferAssociationInfo info, bool flag, int slot = -1)
|
|
{
|
|
ObservableCollection<WaferInfo> wafers = info.ModuleData.WaferManager.Wafers;
|
|
if (slot >= 0) //by wafer
|
|
{
|
|
int index = wafers.Count - slot - 1;
|
|
if (index < wafers.Count)
|
|
{
|
|
if (flag && HasWaferOnSlot(wafers.ToList(), index))
|
|
wafers[index].SequenceName = info.SequenceName;
|
|
else
|
|
wafers[index].SequenceName = string.Empty;
|
|
}
|
|
}
|
|
else //by from-to
|
|
{
|
|
for (int i = info.SlotFrom - 1; i < info.SlotTo; i++)
|
|
{
|
|
int index = wafers.Count - i - 1;
|
|
if (index < wafers.Count)
|
|
{
|
|
if (flag && HasWaferOnSlot(wafers.ToList(), index))
|
|
wafers[index].SequenceName = info.SequenceName;
|
|
else
|
|
wafers[index].SequenceName = string.Empty;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool HasWaferOnSlot(List<WaferInfo> wafers, int index)
|
|
{
|
|
if (wafers[index].WaferStatus == 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
#endregion
|
|
|
|
#region Job operation
|
|
private int _jobRefreashTime = 5;
|
|
private void GetJobList()
|
|
{
|
|
_jobRefreashTime++;
|
|
if (_jobRefreashTime < 5)
|
|
{
|
|
return;
|
|
}
|
|
if (_jobRefreashTime > 5)
|
|
{
|
|
_jobRefreashTime = 0;
|
|
}
|
|
|
|
if (JobListInfoData == null)
|
|
{
|
|
JobListInfoData = new ObservableCollection<JobListInfo>();
|
|
}
|
|
|
|
string sql = $"SELECT guid, wafer_guid, start_time, end_time, recipe_name, lot_name, current_position, status FROM public.autojob_data where start_time>'" + DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd HH:mm:ss") + "' order by start_time asc;";
|
|
DataTable dbData = QueryDataClient.Instance.Service.QueryData(sql);
|
|
if (dbData != null && dbData.Rows.Count > 0)
|
|
{
|
|
JobListInfoData = new ObservableCollection<JobListInfo>();
|
|
|
|
for (int i = 0; i < dbData.Rows.Count; i++)
|
|
{
|
|
JobListInfo item = new JobListInfo()
|
|
{
|
|
Index = i + 1,
|
|
RecipeName = dbData.Rows[i]["recipe_name"].ToString(),
|
|
LotName = dbData.Rows[i]["lot_name"].ToString(),
|
|
Status = dbData.Rows[i]["status"].ToString(),
|
|
CurrentPosition = dbData.Rows[i]["current_position"].ToString(),
|
|
CreateTime = dbData.Rows[i]["start_time"].ToString(),
|
|
WaferID = dbData.Rows[i]["wafer_guid"].ToString(),
|
|
};
|
|
|
|
bool haveInfo = false;
|
|
foreach (var info in JobListInfoData)
|
|
{
|
|
if (info.WaferID == item.WaferID && info.CreateTime == item.CreateTime)
|
|
{
|
|
haveInfo = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!haveInfo)
|
|
{
|
|
JobListInfoData.Insert(0, item);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool JobCheck(string jobID)
|
|
{
|
|
if (jobID.Length == 0)
|
|
{
|
|
DialogBox.ShowWarning("Please create job first.");
|
|
return false;
|
|
}
|
|
else
|
|
return true;
|
|
}
|
|
|
|
public void CreateJob(WaferAssociationInfo info, out string jobID)
|
|
{
|
|
jobID = "";
|
|
|
|
if (LoadWaferAssociation.LotId == "")
|
|
{
|
|
LoadWaferAssociation.LotId = "LoadLock.01";
|
|
}
|
|
|
|
List<string> slotSequence = new List<string>();
|
|
foreach (var wafer in info.ModuleData.WaferManager.Wafers)
|
|
{
|
|
if (wafer.WaferStatus == 1)
|
|
{
|
|
wafer.SequenceName = LoadWaferAssociation.SequenceName;
|
|
wafer.LotID = LoadWaferAssociation.LotId;
|
|
slotSequence.Insert(0, wafer.SequenceName);
|
|
}
|
|
}
|
|
|
|
if (slotSequence.Count > 0)
|
|
{
|
|
if (string.IsNullOrEmpty(jobID))
|
|
jobID = "CJ_Local_Load" + "_" + DateTime.Now.ToString("HHmmss");
|
|
info.LotIdSaved = true;
|
|
WaferAssociationProvider.Instance.CreateJob(jobID, info.ModuleData.ModuleID, slotSequence, LoadWaferAssociation.LotId, true);
|
|
}
|
|
}
|
|
|
|
public void AbortJob(string jobID)
|
|
{
|
|
if (JobCheck(jobID))
|
|
WaferAssociationProvider.Instance.AbortJob(jobID);
|
|
}
|
|
|
|
public void Start(string jobID)
|
|
{
|
|
var selection = DialogBox.ShowDialog(DialogButton.OK | DialogButton.Cancel, DialogType.CONFIRM,
|
|
"Make sure that the LL creates a wafer \r\nMake sure that the LL is in the Online state");
|
|
if (selection == DialogButton.Cancel)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CreateJob(LoadWaferAssociation, out jobID);
|
|
|
|
if (JobCheck(jobID))
|
|
{
|
|
_systemAbort = false;
|
|
WaferAssociationProvider.Instance.Start(jobID);
|
|
}
|
|
}
|
|
|
|
public void Pause(string jobID)
|
|
{
|
|
if (JobCheck(jobID))
|
|
WaferAssociationProvider.Instance.Pause(jobID);
|
|
}
|
|
|
|
public void Resume(string jobID)
|
|
{
|
|
if (JobCheck(jobID))
|
|
WaferAssociationProvider.Instance.Resume(jobID);
|
|
}
|
|
|
|
public void Stop(string jobID)
|
|
{
|
|
if (JobCheck(jobID))
|
|
WaferAssociationProvider.Instance.Stop(jobID);
|
|
}
|
|
|
|
|
|
public void PauseJobList_Click(object info)
|
|
{
|
|
System.Windows.Forms.MessageBox.Show(info.ToString());
|
|
}
|
|
public void ResumeJobList_Click(object info)
|
|
{
|
|
System.Windows.Forms.MessageBox.Show(info.ToString());
|
|
}
|
|
public void AbortJobList_Click(object info)
|
|
{
|
|
System.Windows.Forms.MessageBox.Show(info.ToString());
|
|
}
|
|
#endregion Job operation
|
|
|
|
#region Cassette Operation
|
|
public void CreateWafer(string cassName, string startSlotStr, string endSlotStr)
|
|
{
|
|
int startSlot = 0;
|
|
int endSlot = 0;
|
|
if (Int32.TryParse(startSlotStr, out startSlot) && Int32.TryParse(endSlotStr, out endSlot))
|
|
{
|
|
InvokeClient.Instance.Service.DoOperation($"{cassName}.CreateAll", startSlot, endSlot);
|
|
}
|
|
}
|
|
|
|
public void DeleteWafer(string cassName, string startSlotStr, string endSlotStr)
|
|
{
|
|
int startSlot = 0;
|
|
int endSlot = 0;
|
|
if (Int32.TryParse(startSlotStr, out startSlot) && Int32.TryParse(endSlotStr, out endSlot))
|
|
{
|
|
InvokeClient.Instance.Service.DoOperation($"{cassName}.DeleteAll", startSlot, endSlot);
|
|
}
|
|
}
|
|
|
|
public void MapWafer(string cassName)
|
|
{
|
|
InvokeClient.Instance.Service.DoOperation($"EFEM.MapWafer", cassName);
|
|
}
|
|
|
|
public void MapTray(string cassName)
|
|
{
|
|
InvokeClient.Instance.Service.DoOperation($"EFEM.MapTray", cassName);
|
|
}
|
|
|
|
#endregion
|
|
#endregion
|
|
|
|
#region Signal Tower Buzzer Switch
|
|
|
|
public void SwitchOffBuzzerEx(string sCount, string sInterval, string sRemainTime)
|
|
{
|
|
if (sCount.Trim().Length == 0)
|
|
{
|
|
return;
|
|
}
|
|
if (sInterval.Trim().Length == 0)
|
|
{
|
|
InvokeClient.Instance.Service.DoOperation("PM1.SignalTower.SwitchOffBuzzerEx", sCount);
|
|
}
|
|
else
|
|
{
|
|
if (sRemainTime.Trim().Length == 0)
|
|
{
|
|
InvokeClient.Instance.Service.DoOperation("PM1.SignalTower.SwitchOffBuzzerEx", sCount, sInterval);
|
|
}
|
|
else
|
|
{
|
|
InvokeClient.Instance.Service.DoOperation("PM1.SignalTower.SwitchOffBuzzerEx", sCount, sInterval, sRemainTime);
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
[Subscription("Scheduler.TimeLoad")]
|
|
public double LoadCoolingTime { get; set; }
|
|
|
|
#region Monitor Window
|
|
|
|
|
|
/// <summary>
|
|
/// 打开 Process Monitor
|
|
/// </summary>
|
|
public void ShowProcessMonitorWindow()
|
|
{
|
|
// 如果已经打开,则激活窗口
|
|
var wins = Application.Current.Windows.OfType<ProcessMonitorView>().ToArray();
|
|
|
|
if (wins.Any())
|
|
{
|
|
foreach (var w in wins)
|
|
{
|
|
w.Activate();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var wm = new WindowManager();
|
|
var model = new ProcessMonitorViewModel();
|
|
dynamic settings = new ExpandoObject();
|
|
settings.WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
|
wm.ShowWindow(model, null, settings);
|
|
|
|
}
|
|
}
|
|
public void CheckPM1MonitorWindow()
|
|
{
|
|
|
|
var wins = Application.Current.Windows.OfType<ProcessMonitorView>().ToArray();
|
|
if (wins.Any())
|
|
{
|
|
foreach (var w in wins)
|
|
{
|
|
w.Activate();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 关闭 Process Monitor
|
|
/// </summary>
|
|
public void CloseProcessMonitorWindow()
|
|
{
|
|
var wins = Application.Current.Windows.OfType<ProcessMonitorView>().ToArray();
|
|
if (!wins.Any())
|
|
return;
|
|
|
|
foreach (var w in wins)
|
|
{
|
|
w.Close();
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Aggregated Event。
|
|
/// </summary>
|
|
/// <param name="message"></param>
|
|
public void Handle(ShowCloseMonitorWinEvent message)
|
|
{
|
|
if (message.IsShow)
|
|
// 显示Process监控窗口
|
|
ShowProcessMonitorWindow();
|
|
else
|
|
CloseProcessMonitorWindow();
|
|
}
|
|
#endregion
|
|
}
|
|
}
|