Sic03/SicRT/Equipments/Schedulers/SchedulerModule.cs

654 lines
21 KiB
C#
Raw Normal View History

2022-07-30 08:50:44 +08:00
using System;
using System.Collections.Generic;
using Aitex.Core.Common;
using Aitex.Core.RT.Event;
2022-07-27 19:13:21 +08:00
using Aitex.Core.Util;
2022-07-26 09:41:07 +08:00
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.Schedulers;
using MECF.Framework.Common.SubstrateTrackings;
namespace SicRT.Modules.Schedulers
{
public class SchedulerModule
{
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();
/// <summary>
/// 调度器处于Transfer状态超时。
/// <br/>
/// 如果调度器保持在Transfer任务并超过了指定时间需自动退出Transfer任务。
/// </summary>
protected readonly DeviceTimer TimTransferTaskTimeout;
/// <summary>
/// 检测首次进入Transfer任务的状态。
/// </summary>
protected readonly R_TRIG TrigTransferTaskEntered;
public ModuleName Module => ModuleHelper.Converter(_module);
2022-07-26 09:41:07 +08:00
public virtual bool IsAvailable { get; }
public virtual bool IsOnline { get; }
public virtual bool IsError { get; }
public virtual bool IsReady { get; }
2022-09-07 15:52:00 +08:00
public virtual bool IsService { get; }
2022-08-22 09:48:03 +08:00
2022-07-27 19:13:21 +08:00
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];
2022-07-26 09:41:07 +08:00
protected string _module;
protected TaskType _task = TaskType.None;
protected ModuleName _inProcessRobot;
public SchedulerModule(string module)
{
_module = module;
2022-07-27 19:13:21 +08:00
for (int i = 0; i < firstDetectWaferArriveTrigs.Length; i++)
{
firstDetectWaferArriveTrigs[i] = new R_TRIG();
}
for (int i = 0; i < firstDetectWaferLeaveTrigs.Length; i++)
{
firstDetectWaferLeaveTrigs[i] = new R_TRIG();
}
for (int i = 0; i < firstDetectTrayArriveTrigs.Length; i++)
{
firstDetectTrayArriveTrigs[i] = new R_TRIG();
}
for (int i = 0; i < firstDetectTrayLeaveTrigs.Length; i++)
{
firstDetectTrayLeaveTrigs[i] = new R_TRIG();
}
TimTransferTaskTimeout = new DeviceTimer();
TrigTransferTaskEntered = new R_TRIG();
2022-07-26 09:41:07 +08:00
}
/// <summary>
/// 检查调度器是否空闲。
/// </summary>
/// <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>
/// <returns></returns>
protected bool SuperCheckTaskDone(bool isTaskDone, bool fsmStopped)
{
// Transfer状态需特殊对待。该状态在调度器的CheckTaskDone()中未处理因为机械手的异常可能导致被操作的调度器卡死在Transfer任务中。
// 因此需要建立超时机制如果调度器停留在Transfer状态时间过长则可能是机械手发生异常需要自动退出Transfer任务。
if (_task == TaskType.TransferTarget)
{
if (TimTransferTaskTimeout.IsTimeout())
{
// 强制结束TransferTarget任务
_task = TaskType.None;
TimTransferTaskTimeout.Stop();
isTaskDone = true;
}
else
{
// 调度器仍然在Transfer任务中
return false;
}
}
isTaskDone &= fsmStopped;
if (isTaskDone)
{
if (_task != TaskType.None)
{
LogTaskDone(_task, "");
_task = TaskType.None;
}
return true;
}
if (fsmStopped)
{
LogTaskDone(_task, "Task Failed");
_task = TaskType.None;
return true;
}
return false;
}
2022-07-26 09:41:07 +08:00
protected void LogTaskStart(TaskType cmd, string message)
{
EV.PostInfoLog("Scheduler", $"Task Start: {_module},{cmd} {message}");
2022-07-30 08:50:44 +08:00
2022-07-26 09:41:07 +08:00
}
protected void LogTaskDone(TaskType cmd, string message)
{
EV.PostInfoLog("Scheduler", $"Task Done: {_module},{cmd} {message}");
2022-07-26 09:41:07 +08:00
}
public virtual void ResetTask()
2022-07-26 09:41:07 +08:00
{
lock (SyncRoot)
{
_task = TaskType.None;
TimTransferTaskTimeout.Stop();
}
2022-07-26 09:41:07 +08:00
}
public virtual bool WaitTransfer(ModuleName robot)
2022-07-26 09:41:07 +08:00
{
lock (SyncRoot)
{
_task = TaskType.TransferTarget;
_inProcessRobot = robot;
TimTransferTaskTimeout.Start(30000);
LogTaskStart(_task, $"Note {robot} in transfer");
return true;
}
2022-07-26 09:41:07 +08:00
}
public bool IsWaitTransfer(ModuleName robot)
{
lock (SyncRoot)
{
return _task == TaskType.TransferTarget && _inProcessRobot == robot;
}
2022-07-26 09:41:07 +08:00
}
public virtual bool StopWaitTransfer(ModuleName robot)
2022-07-26 09:41:07 +08:00
{
lock (SyncRoot)
{
LogTaskDone(_task, $"Note {robot} transfer complete");
_inProcessRobot = ModuleName.System;
_task = TaskType.None;
TimTransferTaskTimeout.Stop();
return true;
}
2022-07-26 09:41:07 +08:00
}
2022-07-30 08:50:44 +08:00
public WaferInfo GetWaferInfo(int slot)
{
lock (SyncRoot)
{
return WaferManager.Instance.GetWafer(ModuleHelper.Converter(_module), slot);
}
2022-07-30 08:50:44 +08:00
}
public bool CheckWaferStatus(int slot, WaferStatus waferStatus)
{
lock (SyncRoot)
{
return WaferManager.Instance.CheckWafer(ModuleHelper.Converter(_module), slot, waferStatus);
}
2022-07-30 08:50:44 +08:00
}
2022-07-26 09:41:07 +08:00
public bool HasWafer(int slot)
{
lock (SyncRoot)
{
return WaferManager.Instance.CheckHasWafer(ModuleHelper.Converter(_module), slot);
}
2022-07-26 09:41:07 +08:00
}
public bool NoWafer(int slot)
{
lock (SyncRoot)
{
return WaferManager.Instance.CheckNoWafer(ModuleHelper.Converter(_module), slot);
}
2022-07-26 09:41:07 +08:00
}
public bool HasTray(int slot)
{
lock (SyncRoot)
{
return WaferManager.Instance.CheckHasTray(ModuleHelper.Converter(_module), slot);
}
2022-07-26 09:41:07 +08:00
}
public bool NoTray(int slot)
{
lock (SyncRoot)
{
return WaferManager.Instance.CheckNoTray(ModuleHelper.Converter(_module), slot);
}
2022-07-26 09:41:07 +08:00
}
2022-07-27 19:13:21 +08:00
public bool FirstDetectWaferArrive(int slot)
{
firstDetectWaferArriveTrigs[slot].CLK = HasWafer(slot);
return firstDetectWaferArriveTrigs[slot].Q;
2022-07-27 19:13:21 +08:00
}
public bool FirstDetectWaferLeave(int slot)
{
firstDetectWaferLeaveTrigs[slot].CLK = NoWafer(slot);
return firstDetectWaferLeaveTrigs[slot].Q;
2022-07-27 19:13:21 +08:00
}
public bool FirstDetectTrayArrive(int slot)
{
firstDetectTrayArriveTrigs[slot].CLK = HasTray(slot);
return firstDetectTrayArriveTrigs[slot].Q;
2022-07-27 19:13:21 +08:00
}
public bool FirstDetectTrayLeave(int slot)
{
firstDetectTrayLeaveTrigs[slot].CLK = NoTray(slot);
return firstDetectTrayLeaveTrigs[slot].Q;
}
2022-07-30 08:50:44 +08:00
public bool HasTrayAndExceedProcessCount(int slot)
{
lock (SyncRoot)
{
WaferInfo wi = WaferManager.Instance.GetWafer(ModuleHelper.Converter(_module), slot);
if (wi == null)
return false;
return wi.TrayState == WaferTrayStatus.Normal && wi.TrayProcessCount <= 0;
}
2022-07-30 08:50:44 +08:00
}
public bool HasTrayAndNotExceedProcessCount(int slot)
{
lock (SyncRoot)
{
WaferInfo wi = WaferManager.Instance.GetWafer(ModuleHelper.Converter(_module), slot);
if (wi == null)
return false;
return wi.TrayState == WaferTrayStatus.Normal && wi.TrayProcessCount > 0;
}
2022-07-30 08:50:44 +08:00
}
public virtual bool CheckWaferNextStepIsThis(ModuleName module, int slot)
{
lock (SyncRoot)
{
if (!WaferManager.Instance.CheckHasWafer(module, slot))
return false;
2022-07-30 08:50:44 +08:00
WaferInfo wafer = WaferManager.Instance.GetWafer(module, slot);
2022-07-30 08:50:44 +08:00
if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
return false;
2022-07-30 08:50:44 +08:00
if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
return false;
2022-07-30 08:50:44 +08:00
if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(Module))
return false;
2022-07-30 08:50:44 +08:00
return true;
}
2022-07-30 08:50:44 +08:00
}
/// <summary>
/// 判断下一步的模块是否有Wafer
/// </summary>
/// <param name="slot"></param>
/// <returns></returns>
public virtual bool CheckWaferNextStepModuleNoWafer(int slot)
{
lock (SyncRoot)
{
if (!WaferManager.Instance.CheckHasWafer(Module, slot))
return false;
2022-07-30 08:50:44 +08:00
WaferInfo wafer = WaferManager.Instance.GetWafer(Module, slot);
2022-07-30 08:50:44 +08:00
if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
return false;
2022-07-30 08:50:44 +08:00
if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
return false;
2022-07-30 08:50:44 +08:00
List<ModuleName> lstModuleName = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules;
if (lstModuleName.Count > 0)
2022-07-30 08:50:44 +08:00
{
for (int i = 0; i < lstModuleName.Count; i++)
2022-07-30 08:50:44 +08:00
{
if (WaferManager.Instance.CheckNoWafer(lstModuleName[i], 0))
{
return true;
}
2022-07-30 08:50:44 +08:00
}
}
return false;
2022-07-30 08:50:44 +08:00
}
}
public virtual bool CheckWaferNextStepModuleNoTray(int slot)
{
lock (SyncRoot)
{
if (!WaferManager.Instance.CheckHasWafer(Module, slot))
return false;
2022-07-30 08:50:44 +08:00
WaferInfo wafer = WaferManager.Instance.GetWafer(Module, slot);
2022-07-30 08:50:44 +08:00
if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
return false;
2022-07-30 08:50:44 +08:00
if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
return false;
2022-07-30 08:50:44 +08:00
List<ModuleName> lstModuleName = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules;
if (lstModuleName.Count > 0)
2022-07-30 08:50:44 +08:00
{
for (int j = 0; j < lstModuleName.Count; j++)
2022-07-30 08:50:44 +08:00
{
if (lstModuleName[j] == ModuleName.Buffer)
2022-07-30 08:50:44 +08:00
{
string strSots = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep]
.StepParameter["SlotSelection"].ToString();
if (string.IsNullOrEmpty(strSots))
{
return false;
}
2022-07-30 08:50:44 +08:00
string[] bufferSlots = strSots.Split(',');
for (int k = 0; k < bufferSlots.Length; k++)
2022-07-30 08:50:44 +08:00
{
if (Int32.TryParse(bufferSlots[k], out int bufferSlot))
2022-07-30 08:50:44 +08:00
{
if (WaferManager.Instance.CheckNoTray(ModuleName.Buffer, bufferSlot - 1))
{
return true;
}
2022-07-30 08:50:44 +08:00
}
}
}
else if (WaferManager.Instance.CheckNoTray(lstModuleName[j], 0))
{
return true;
}
2022-07-30 08:50:44 +08:00
}
}
return false;
2022-07-30 08:50:44 +08:00
}
}
/// <summary>
/// 判断Wafer的步骤是否都完成了
/// </summary>
/// <param name="waferModule"></param>
/// <param name="waferSlot"></param>
/// <returns></returns>
public virtual bool CheckWaferSequenceStepDone(int slot)
{
lock (SyncRoot)
2022-07-30 08:50:44 +08:00
{
WaferInfo wafer = WaferManager.Instance.GetWafer(Module, slot);
2022-07-30 08:50:44 +08:00
if (wafer.IsEmpty)
{
return false;
}
2022-07-30 08:50:44 +08:00
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;
}
2022-07-30 08:50:44 +08:00
}
public virtual bool CheckWaferNeedProcess(int waferSlot, ModuleName processIn = ModuleName.System)
{
lock (SyncRoot)
{
WaferInfo wafer = WaferManager.Instance.GetWafer(Module, waferSlot);
2022-07-30 08:50:44 +08:00
if (wafer.IsEmpty)
return false;
2022-07-30 08:50:44 +08:00
if (wafer.Status == WaferStatus.Dummy && wafer.ProcessState == EnumWaferProcessStatus.Wait)
2022-07-30 08:50:44 +08:00
{
if (ModuleHelper.IsPm(processIn))
{
return (CheckNeedRunClean(out bool withWafer, out _) && withWafer);
}
return true;
2022-07-30 08:50:44 +08:00
}
if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null ||
wafer.ProcessJob.Sequence.Steps == null)
return false;
2022-07-30 08:50:44 +08:00
if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count ||
wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules == null)
return false;
2022-07-30 08:50:44 +08:00
if (processIn != ModuleName.System && !wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep]
.StepModules.Contains(processIn))
return false;
2022-07-30 08:50:44 +08:00
bool hasPm = false;
for (int i = wafer.NextSequenceStep; i < wafer.ProcessJob.Sequence.Steps.Count; i++)
2022-07-30 08:50:44 +08:00
{
foreach (var stepModule in wafer.ProcessJob.Sequence.Steps[i].StepModules)
2022-07-30 08:50:44 +08:00
{
if (ModuleHelper.IsPm(stepModule))
{
hasPm = true;
break;
}
2022-07-30 08:50:44 +08:00
}
if (hasPm)
break;
2022-07-30 08:50:44 +08:00
}
if (processIn == ModuleName.System && !hasPm)
return false;
2022-07-30 08:50:44 +08:00
return true;
}
2022-07-30 08:50:44 +08:00
}
public virtual bool CheckNeedRunClean(out bool withWafer, out string recipeName)
{
lock (SyncRoot)
{
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;
// }
// }
//}
2022-07-30 08:50:44 +08:00
return false;
}
2022-07-30 08:50:44 +08:00
}
2022-07-26 09:41:07 +08:00
public virtual bool IsReadyForPick(ModuleName robot, int slot)
{
lock (SyncRoot)
{
return true;
}
2022-07-26 09:41:07 +08:00
}
public virtual bool IsReadyForPlace(ModuleName robot, int slot)
{
lock (SyncRoot)
{
return true;
}
2022-07-26 09:41:07 +08:00
}
public virtual bool PrepareTransfer(ModuleName robot, EnumTransferType type, int slot)
{
lock (SyncRoot)
{
return true;
}
2022-07-26 09:41:07 +08:00
}
public virtual bool PostTransfer(ModuleName robot, EnumTransferType type, int slot)
{
lock (SyncRoot)
{
return true;
}
2022-07-26 09:41:07 +08:00
}
public virtual bool Process(string recipeName, bool isCleanRecipe, bool withDummyWafer)
{
lock (SyncRoot)
{
return true;
}
2022-07-26 09:41:07 +08:00
}
2022-07-30 08:50:44 +08:00
public virtual bool Cooling(bool coolingType, int coolingTime)
2022-07-26 09:41:07 +08:00
{
lock (SyncRoot)
{
return true;
}
2022-07-26 09:41:07 +08:00
}
public virtual bool Aligning()
{
lock (SyncRoot)
{
return true;
}
2022-07-26 09:41:07 +08:00
}
public virtual bool WarmUp(int warmUpTime)
{
lock (SyncRoot)
{
return true;
}
2022-07-26 09:41:07 +08:00
}
2022-07-27 19:13:21 +08:00
public virtual bool CheckWaferTraySeparated()
2022-07-26 09:41:07 +08:00
{
lock (SyncRoot)
{
return true;
}
2022-07-26 09:41:07 +08:00
}
public virtual bool CheckWaferTrayGrouped()
{
lock (SyncRoot)
{
return true;
}
2022-07-26 09:41:07 +08:00
}
public virtual bool CheckSlitValveClosed() //检查闸板阀是否关闭
{
lock (SyncRoot)
{
return true;
}
2022-07-26 09:41:07 +08:00
}
}
}