2023-05-05 13:30:20 +08:00
|
|
|
|
using System.Collections.Generic;
|
2023-03-03 15:42:13 +08:00
|
|
|
|
using Aitex.Core.Common;
|
|
|
|
|
using Aitex.Core.RT.Event;
|
|
|
|
|
using Aitex.Core.Util;
|
|
|
|
|
using MECF.Framework.Common.Equipment;
|
|
|
|
|
using MECF.Framework.Common.Schedulers;
|
|
|
|
|
using MECF.Framework.Common.SubstrateTrackings;
|
|
|
|
|
|
|
|
|
|
namespace SicRT.Modules.Schedulers
|
|
|
|
|
{
|
|
|
|
|
public class SchedulerModule
|
|
|
|
|
{
|
2023-05-05 16:09:03 +08:00
|
|
|
|
#region Variables
|
|
|
|
|
|
2023-03-03 15:42:13 +08:00
|
|
|
|
protected enum TaskType
|
|
|
|
|
{
|
|
|
|
|
None,
|
|
|
|
|
|
|
|
|
|
PrepareTransfer,
|
|
|
|
|
|
|
|
|
|
Pick,
|
|
|
|
|
|
|
|
|
|
Place,
|
|
|
|
|
|
|
|
|
|
PickAndPlace,
|
|
|
|
|
|
|
|
|
|
Preprocess,
|
|
|
|
|
Process,
|
|
|
|
|
PostProcess,
|
|
|
|
|
|
|
|
|
|
OpenCover,
|
|
|
|
|
CloseCover,
|
|
|
|
|
|
|
|
|
|
Load,
|
|
|
|
|
Unload,
|
|
|
|
|
|
|
|
|
|
Align,
|
|
|
|
|
|
|
|
|
|
TransferTarget,
|
|
|
|
|
|
|
|
|
|
Cooling,
|
|
|
|
|
|
|
|
|
|
WarmUp,
|
|
|
|
|
|
|
|
|
|
Vent,
|
|
|
|
|
Pump,
|
|
|
|
|
Purge,
|
|
|
|
|
Group,
|
|
|
|
|
Separate,
|
|
|
|
|
Map
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 访问变量时先锁定,避免多线程竞争问题。
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected readonly object SyncRoot = new object();
|
|
|
|
|
|
|
|
|
|
private R_TRIG[] firstDetectWaferArriveTrigs = new R_TRIG[25];
|
|
|
|
|
private R_TRIG[] firstDetectWaferLeaveTrigs = new R_TRIG[25];
|
|
|
|
|
private R_TRIG[] firstDetectTrayArriveTrigs = new R_TRIG[25];
|
|
|
|
|
private R_TRIG[] firstDetectTrayLeaveTrigs = new R_TRIG[25];
|
|
|
|
|
|
|
|
|
|
protected string _module;
|
2023-05-05 16:09:03 +08:00
|
|
|
|
|
2023-03-03 15:42:13 +08:00
|
|
|
|
protected TaskType _task = TaskType.None;
|
2023-05-05 16:09:03 +08:00
|
|
|
|
|
2023-05-05 13:30:20 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 检测调度器TransferTarget任务是否超时。
|
|
|
|
|
/// </summary>
|
|
|
|
|
private readonly DeviceTimer _timTransferTargetStatusTimeout;
|
2023-03-03 15:42:13 +08:00
|
|
|
|
|
2023-05-05 16:09:03 +08:00
|
|
|
|
private ModuleName _inProcessRobot;
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Constructors
|
2023-03-03 15:42:13 +08:00
|
|
|
|
|
2023-05-05 16:09:03 +08:00
|
|
|
|
protected SchedulerModule(string module)
|
2023-03-03 15:42:13 +08:00
|
|
|
|
{
|
|
|
|
|
_module = module;
|
2023-05-05 16:09:03 +08:00
|
|
|
|
for (var i = 0; i < firstDetectWaferArriveTrigs.Length; i++)
|
2023-03-03 15:42:13 +08:00
|
|
|
|
{
|
|
|
|
|
firstDetectWaferArriveTrigs[i] = new R_TRIG();
|
|
|
|
|
}
|
2023-05-05 16:09:03 +08:00
|
|
|
|
for (var i = 0; i < firstDetectWaferLeaveTrigs.Length; i++)
|
2023-03-03 15:42:13 +08:00
|
|
|
|
{
|
|
|
|
|
firstDetectWaferLeaveTrigs[i] = new R_TRIG();
|
|
|
|
|
}
|
2023-05-05 16:09:03 +08:00
|
|
|
|
for (var i = 0; i < firstDetectTrayArriveTrigs.Length; i++)
|
2023-03-03 15:42:13 +08:00
|
|
|
|
{
|
|
|
|
|
firstDetectTrayArriveTrigs[i] = new R_TRIG();
|
|
|
|
|
}
|
2023-05-05 16:09:03 +08:00
|
|
|
|
for (var i = 0; i < firstDetectTrayLeaveTrigs.Length; i++)
|
2023-03-03 15:42:13 +08:00
|
|
|
|
{
|
|
|
|
|
firstDetectTrayLeaveTrigs[i] = new R_TRIG();
|
|
|
|
|
}
|
2023-05-05 13:30:20 +08:00
|
|
|
|
|
|
|
|
|
_timTransferTargetStatusTimeout = new DeviceTimer();
|
2023-03-03 15:42:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-05 16:09:03 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Properties
|
|
|
|
|
|
|
|
|
|
public ModuleName Module => ModuleHelper.Converter(_module);
|
|
|
|
|
|
|
|
|
|
public virtual bool IsAvailable { get; }
|
|
|
|
|
public virtual bool IsOnline { get; }
|
|
|
|
|
public virtual bool IsError { get; }
|
|
|
|
|
|
|
|
|
|
public virtual bool IsReady { get; }
|
|
|
|
|
|
|
|
|
|
public virtual bool IsService { get; }
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Methods
|
|
|
|
|
|
2023-03-03 15:42:13 +08:00
|
|
|
|
public string GetTask()
|
|
|
|
|
{
|
|
|
|
|
return _task.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2023-05-05 13:30:20 +08:00
|
|
|
|
/// 检查调度器是否空闲。
|
2023-03-03 15:42:13 +08:00
|
|
|
|
/// </summary>
|
2023-05-05 13:30:20 +08:00
|
|
|
|
/// <Remarks>
|
|
|
|
|
/// 调度器空闲的条件除调度器无任务执行,还需要判断Module的状态是否为Idle或Error。
|
|
|
|
|
/// 因为如果调度器执行过程中,Module发生错误,也应该将调度器标记为空闲,否则调度器可能卡死而导致Auto流程无法继续。
|
|
|
|
|
/// 以下为调度器和Module可能出现冲突的状态,和判决方法:
|
|
|
|
|
/// <para>1. 如果调度器无任务,但Module还未Idle,则说明上个Routine还未执行完毕,则认为Task还未完成。</para>
|
|
|
|
|
/// <para>2. 如果调度器有任务,但Module已经Idle或Error,则说明Routine已执行完毕,但可能出错,则认为Task完成。</para>
|
|
|
|
|
/// </Remarks>
|
|
|
|
|
/// <param name="isTaskDone">调度器执行的任务是否结束。</param>
|
|
|
|
|
/// <param name="fsmStopped">调度器关联的Module的状态机是否Idle或Alarm</param>
|
2023-03-03 15:42:13 +08:00
|
|
|
|
/// <returns></returns>
|
2023-05-05 13:30:20 +08:00
|
|
|
|
protected bool SuperCheckTaskDone(bool isTaskDone, bool fsmStopped)
|
2023-03-03 15:42:13 +08:00
|
|
|
|
{
|
2023-05-05 13:30:20 +08:00
|
|
|
|
// Transfer状态需特殊对待。该状态在调度器的CheckTaskDone()中未处理,因为机械手的异常可能导致被操作的调度器卡死在Transfer任务中。
|
|
|
|
|
// 因此需要建立超时机制,如果调度器停留在Transfer状态时间过长,则可能是机械手发生异常,需要自动退出Transfer任务。
|
|
|
|
|
if (_task == TaskType.TransferTarget)
|
|
|
|
|
{
|
|
|
|
|
if (_timTransferTargetStatusTimeout.IsTimeout())
|
|
|
|
|
{
|
|
|
|
|
// 强制结束TransferTarget任务
|
|
|
|
|
_task = TaskType.None;
|
|
|
|
|
_timTransferTargetStatusTimeout.Stop();
|
|
|
|
|
isTaskDone = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// 调度器仍然在Transfer任务中
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-03 15:42:13 +08:00
|
|
|
|
|
2023-05-05 13:30:20 +08:00
|
|
|
|
isTaskDone &= fsmStopped;
|
|
|
|
|
|
|
|
|
|
if (isTaskDone)
|
2023-03-03 15:42:13 +08:00
|
|
|
|
{
|
|
|
|
|
if (_task != TaskType.None)
|
|
|
|
|
{
|
|
|
|
|
LogTaskDone(_task, "");
|
|
|
|
|
_task = TaskType.None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fsmStopped)
|
|
|
|
|
{
|
|
|
|
|
LogTaskDone(_task, "Task Failed");
|
|
|
|
|
_task = TaskType.None;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-05 13:30:20 +08:00
|
|
|
|
|
2023-03-03 15:42:13 +08:00
|
|
|
|
protected void LogTaskStart(TaskType cmd, string message)
|
|
|
|
|
{
|
2023-05-05 16:09:03 +08:00
|
|
|
|
EV.PostInfoLog("Scheduler", $"Task Start: {_module},{cmd} {message}");
|
2023-03-03 15:42:13 +08:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
protected void LogTaskDone(TaskType cmd, string message)
|
|
|
|
|
{
|
2023-05-05 16:09:03 +08:00
|
|
|
|
EV.PostInfoLog("Scheduler", $"Task Done: {_module},{cmd} {message}");
|
2023-03-03 15:42:13 +08:00
|
|
|
|
}
|
2023-05-05 16:09:03 +08:00
|
|
|
|
public virtual void ResetTask()
|
2023-03-03 15:42:13 +08:00
|
|
|
|
{
|
|
|
|
|
_task = TaskType.None;
|
2023-05-05 13:30:20 +08:00
|
|
|
|
_timTransferTargetStatusTimeout.Stop();
|
2023-03-03 15:42:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool WaitTransfer(ModuleName robot)
|
|
|
|
|
{
|
|
|
|
|
_task = TaskType.TransferTarget;
|
|
|
|
|
_inProcessRobot = robot;
|
2023-05-05 13:30:20 +08:00
|
|
|
|
_timTransferTargetStatusTimeout.Start(30000);
|
2023-03-03 15:42:13 +08:00
|
|
|
|
LogTaskStart(_task, $"Note {robot} in transfer");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsWaitTransfer(ModuleName robot)
|
|
|
|
|
{
|
|
|
|
|
return _task == TaskType.TransferTarget && _inProcessRobot == robot;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-05 16:09:03 +08:00
|
|
|
|
public virtual bool StopWaitTransfer(ModuleName robot)
|
2023-03-03 15:42:13 +08:00
|
|
|
|
{
|
|
|
|
|
LogTaskDone(_task, $"Note {robot} transfer complete");
|
|
|
|
|
_inProcessRobot = ModuleName.System;
|
2023-05-05 13:30:20 +08:00
|
|
|
|
_timTransferTargetStatusTimeout.Stop();
|
2023-03-03 15:42:13 +08:00
|
|
|
|
_task = TaskType.None;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-13 17:37:55 +08:00
|
|
|
|
public WaferInfoRt GetWaferInfo(int slot)
|
2023-03-03 15:42:13 +08:00
|
|
|
|
{
|
|
|
|
|
return WaferManager.Instance.GetWafer(ModuleHelper.Converter(_module), slot);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool CheckWaferStatus(int slot, WaferStatus waferStatus)
|
|
|
|
|
{
|
|
|
|
|
return WaferManager.Instance.CheckWafer(ModuleHelper.Converter(_module), slot, waferStatus);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool HasWafer(int slot)
|
|
|
|
|
{
|
|
|
|
|
return WaferManager.Instance.CheckHasWafer(ModuleHelper.Converter(_module), slot);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool NoWafer(int slot)
|
|
|
|
|
{
|
|
|
|
|
return WaferManager.Instance.CheckNoWafer(ModuleHelper.Converter(_module), slot);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool HasTray(int slot)
|
|
|
|
|
{
|
|
|
|
|
return WaferManager.Instance.CheckHasTray(ModuleHelper.Converter(_module), slot);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool NoTray(int slot)
|
|
|
|
|
{
|
|
|
|
|
return WaferManager.Instance.CheckNoTray(ModuleHelper.Converter(_module), slot);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool FirstDetectWaferArrive(int slot)
|
|
|
|
|
{
|
|
|
|
|
firstDetectWaferArriveTrigs[slot].CLK = HasWafer(slot);
|
|
|
|
|
return firstDetectWaferArriveTrigs[slot].Q;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool FirstDetectWaferLeave(int slot)
|
|
|
|
|
{
|
|
|
|
|
firstDetectWaferLeaveTrigs[slot].CLK = NoWafer(slot);
|
|
|
|
|
return firstDetectWaferLeaveTrigs[slot].Q;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool FirstDetectTrayArrive(int slot)
|
|
|
|
|
{
|
|
|
|
|
firstDetectTrayArriveTrigs[slot].CLK = HasTray(slot);
|
|
|
|
|
return firstDetectTrayArriveTrigs[slot].Q;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool FirstDetectTrayLeave(int slot)
|
|
|
|
|
{
|
|
|
|
|
firstDetectTrayLeaveTrigs[slot].CLK = NoTray(slot);
|
|
|
|
|
return firstDetectTrayLeaveTrigs[slot].Q;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool HasTrayAndExceedProcessCount(int slot)
|
|
|
|
|
{
|
2023-03-13 17:37:55 +08:00
|
|
|
|
var wi = WaferManager.Instance.GetWafer(ModuleHelper.Converter(_module), slot);
|
2023-03-03 15:42:13 +08:00
|
|
|
|
return wi.TrayState == WaferTrayStatus.Normal && wi.TrayProcessCount <=0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool HasTrayAndNotExceedProcessCount(int slot)
|
|
|
|
|
{
|
2023-03-13 17:37:55 +08:00
|
|
|
|
var wi = WaferManager.Instance.GetWafer(ModuleHelper.Converter(_module), slot);
|
2023-03-03 15:42:13 +08:00
|
|
|
|
return wi.TrayState == WaferTrayStatus.Normal && wi.TrayProcessCount >0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual bool CheckWaferNextStepIsThis(ModuleName module, int slot)
|
|
|
|
|
{
|
|
|
|
|
if (!WaferManager.Instance.CheckHasWafer(module, slot))
|
|
|
|
|
return false;
|
|
|
|
|
|
2023-03-13 17:37:55 +08:00
|
|
|
|
var wafer = WaferManager.Instance.GetWafer(module, slot);
|
2023-03-03 15:42:13 +08:00
|
|
|
|
|
|
|
|
|
if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(Module))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 判断下一步的模块是否有Wafer
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="slot"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public virtual bool CheckWaferNextStepModuleNoWafer(int slot)
|
|
|
|
|
{
|
|
|
|
|
if (!WaferManager.Instance.CheckHasWafer(Module, slot))
|
|
|
|
|
return false;
|
|
|
|
|
|
2023-03-13 17:37:55 +08:00
|
|
|
|
var wafer = WaferManager.Instance.GetWafer(Module, slot);
|
2023-03-03 15:42:13 +08:00
|
|
|
|
|
|
|
|
|
if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
List<ModuleName> lstModuleName = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules;
|
|
|
|
|
if (lstModuleName.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < lstModuleName.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (WaferManager.Instance.CheckNoWafer(lstModuleName[i], 0))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual bool CheckWaferNextStepModuleNoTray(int slot)
|
|
|
|
|
{
|
|
|
|
|
if (!WaferManager.Instance.CheckHasWafer(Module, slot))
|
|
|
|
|
return false;
|
|
|
|
|
|
2023-03-13 17:37:55 +08:00
|
|
|
|
var wafer = WaferManager.Instance.GetWafer(Module, slot);
|
2023-03-03 15:42:13 +08:00
|
|
|
|
|
|
|
|
|
if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
List<ModuleName> lstModuleName = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules;
|
|
|
|
|
if (lstModuleName.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
for (int j = 0; j < lstModuleName.Count; j++)
|
|
|
|
|
{
|
|
|
|
|
if (lstModuleName[j] == ModuleName.Buffer)
|
|
|
|
|
{
|
|
|
|
|
if (CheckWaferNeedProcess(slot, ModuleName.PM1))
|
|
|
|
|
{
|
|
|
|
|
if (WaferManager.Instance.CheckNoTray(ModuleName.Buffer, 0))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (CheckWaferNeedProcess(slot, ModuleName.PM2))
|
|
|
|
|
{
|
|
|
|
|
if (WaferManager.Instance.CheckNoTray(ModuleName.Buffer, 1))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (WaferManager.Instance.CheckNoTray(lstModuleName[j], 0))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2023-05-05 16:09:03 +08:00
|
|
|
|
/// 检查指定槽位的Wafer是否完成Sequence。
|
2023-03-03 15:42:13 +08:00
|
|
|
|
/// </summary>
|
2023-05-05 16:09:03 +08:00
|
|
|
|
/// <param name="slot">槽位</param>
|
2023-03-03 15:42:13 +08:00
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public virtual bool CheckWaferSequenceStepDone(int slot)
|
|
|
|
|
{
|
2023-03-13 17:37:55 +08:00
|
|
|
|
var wafer = WaferManager.Instance.GetWafer(Module, slot);
|
2023-03-03 15:42:13 +08:00
|
|
|
|
|
|
|
|
|
if (wafer.IsEmpty)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count && wafer.ProcessJob.Sequence.Steps.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual bool CheckWaferNeedProcess(int waferSlot, ModuleName processIn = ModuleName.System)
|
|
|
|
|
{
|
2023-03-13 17:37:55 +08:00
|
|
|
|
var wafer = WaferManager.Instance.GetWafer(Module, waferSlot);
|
2023-03-03 15:42:13 +08:00
|
|
|
|
|
|
|
|
|
if (wafer.IsEmpty)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//if (wafer.Status == WaferStatus.Dummy && wafer.ProcessState == EnumWaferProcessStatus.Wait)
|
|
|
|
|
//{
|
|
|
|
|
// if (ModuleHelper.IsPm(processIn))
|
|
|
|
|
// {
|
|
|
|
|
// return (CheckNeedRunClean(out bool withWafer, out _) && withWafer);
|
|
|
|
|
// }
|
|
|
|
|
// return true;
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null || wafer.ProcessJob.Sequence.Steps == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count || wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for (int i = wafer.NextSequenceStep; i < wafer.ProcessJob.Sequence.Steps.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
foreach (var stepModule in wafer.ProcessJob.Sequence.Steps[i].StepModules)
|
|
|
|
|
{
|
|
|
|
|
if (ModuleHelper.IsPm(stepModule))
|
|
|
|
|
{
|
|
|
|
|
if (processIn != ModuleName.System)
|
|
|
|
|
{
|
|
|
|
|
return stepModule == processIn ? true : false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual bool CheckNeedRunClean(out bool withWafer, out string recipeName)
|
|
|
|
|
{
|
|
|
|
|
recipeName = string.Empty;
|
|
|
|
|
withWafer = false;
|
|
|
|
|
|
|
|
|
|
//SequenceInfo seq = GetCurrentSequenceInfo();
|
|
|
|
|
//int waferProcessed = StatsDataManager.Instance.GetValue($"{Module}.WaferProcessedSincePreviousClean");
|
|
|
|
|
|
|
|
|
|
//if (seq == null)
|
|
|
|
|
// return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//foreach (var stepInfo in seq.Steps)
|
|
|
|
|
//{
|
|
|
|
|
// if (!stepInfo.StepModules.Contains(Module))
|
|
|
|
|
// continue;
|
|
|
|
|
|
|
|
|
|
// if (stepInfo.StepParameter.ContainsKey("CleanIntervalWaferless")
|
|
|
|
|
// && int.TryParse((string)stepInfo.StepParameter["CleanIntervalWaferless"], out int interval)
|
|
|
|
|
// && stepInfo.StepParameter.ContainsKey("CleanRecipeWaferless")
|
|
|
|
|
// && !string.IsNullOrEmpty((string)stepInfo.StepParameter["CleanRecipeWaferless"]))
|
|
|
|
|
// {
|
|
|
|
|
// if (interval > 0 && waferProcessed >= interval)
|
|
|
|
|
// {
|
|
|
|
|
// recipeName = (string)stepInfo.StepParameter["CleanRecipeWaferless"];
|
|
|
|
|
// withWafer = false;
|
|
|
|
|
// return true;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if (stepInfo.StepParameter.ContainsKey("CleanIntervalWafer")
|
|
|
|
|
// && int.TryParse((string)stepInfo.StepParameter["CleanIntervalWafer"], out interval)
|
|
|
|
|
// && stepInfo.StepParameter.ContainsKey("CleanRecipeWafer")
|
|
|
|
|
// && !string.IsNullOrEmpty((string)stepInfo.StepParameter["CleanRecipeWafer"]))
|
|
|
|
|
// {
|
|
|
|
|
// if (interval > 0 && waferProcessed >= interval)
|
|
|
|
|
// {
|
|
|
|
|
// recipeName = (string)stepInfo.StepParameter["CleanRecipeWafer"];
|
|
|
|
|
// withWafer = true;
|
|
|
|
|
// return true;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual bool IsReadyForPick(ModuleName robot, int slot)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual bool IsReadyForPlace(ModuleName robot, int slot)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual bool PrepareTransfer(ModuleName robot, EnumTransferType type, int slot)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual bool PostTransfer(ModuleName robot, EnumTransferType type, int slot)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual bool Process(string recipeName, bool isCleanRecipe, bool withDummyWafer)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual bool Cooling(bool coolingType, int coolingTime)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public virtual bool Aligning()
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual bool WarmUp(int warmUpTime)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public virtual bool CheckWaferTraySeparated()
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual bool CheckWaferTrayGrouped()
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual bool CheckSlitValveClosed() //检查闸板阀是否关闭
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-05-05 16:09:03 +08:00
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2023-03-03 15:42:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|