Sic03/SicRT/Equipments/Schedulers/SchedulerModule.cs

654 lines
21 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
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
{
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);
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; }
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;
protected TaskType _task = TaskType.None;
protected ModuleName _inProcessRobot;
public SchedulerModule(string module)
{
_module = module;
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();
}
/// <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;
}
protected void LogTaskStart(TaskType cmd, string message)
{
EV.PostInfoLog("Scheduler", $"Task Start: {_module},{cmd} {message}");
}
protected void LogTaskDone(TaskType cmd, string message)
{
EV.PostInfoLog("Scheduler", $"Task Done: {_module},{cmd} {message}");
}
public virtual void ResetTask()
{
lock (SyncRoot)
{
_task = TaskType.None;
TimTransferTaskTimeout.Stop();
}
}
public virtual bool WaitTransfer(ModuleName robot)
{
lock (SyncRoot)
{
_task = TaskType.TransferTarget;
_inProcessRobot = robot;
TimTransferTaskTimeout.Start(30000);
LogTaskStart(_task, $"Note {robot} in transfer");
return true;
}
}
public bool IsWaitTransfer(ModuleName robot)
{
lock (SyncRoot)
{
return _task == TaskType.TransferTarget && _inProcessRobot == robot;
}
}
public virtual bool StopWaitTransfer(ModuleName robot)
{
lock (SyncRoot)
{
LogTaskDone(_task, $"Note {robot} transfer complete");
_inProcessRobot = ModuleName.System;
_task = TaskType.None;
TimTransferTaskTimeout.Stop();
return true;
}
}
public WaferInfo GetWaferInfo(int slot)
{
lock (SyncRoot)
{
return WaferManager.Instance.GetWafer(ModuleHelper.Converter(_module), slot);
}
}
public bool CheckWaferStatus(int slot, WaferStatus waferStatus)
{
lock (SyncRoot)
{
return WaferManager.Instance.CheckWafer(ModuleHelper.Converter(_module), slot, waferStatus);
}
}
public bool HasWafer(int slot)
{
lock (SyncRoot)
{
return WaferManager.Instance.CheckHasWafer(ModuleHelper.Converter(_module), slot);
}
}
public bool NoWafer(int slot)
{
lock (SyncRoot)
{
return WaferManager.Instance.CheckNoWafer(ModuleHelper.Converter(_module), slot);
}
}
public bool HasTray(int slot)
{
lock (SyncRoot)
{
return WaferManager.Instance.CheckHasTray(ModuleHelper.Converter(_module), slot);
}
}
public bool NoTray(int slot)
{
lock (SyncRoot)
{
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)
{
lock (SyncRoot)
{
WaferInfo wi = WaferManager.Instance.GetWafer(ModuleHelper.Converter(_module), slot);
if (wi == null)
return false;
return wi.TrayState == WaferTrayStatus.Normal && wi.TrayProcessCount <= 0;
}
}
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;
}
}
public virtual bool CheckWaferNextStepIsThis(ModuleName module, int slot)
{
lock (SyncRoot)
{
if (!WaferManager.Instance.CheckHasWafer(module, slot))
return false;
WaferInfo wafer = WaferManager.Instance.GetWafer(module, slot);
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)
{
lock (SyncRoot)
{
if (!WaferManager.Instance.CheckHasWafer(Module, slot))
return false;
WaferInfo wafer = WaferManager.Instance.GetWafer(Module, slot);
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)
{
lock (SyncRoot)
{
if (!WaferManager.Instance.CheckHasWafer(Module, slot))
return false;
WaferInfo wafer = WaferManager.Instance.GetWafer(Module, slot);
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)
{
string strSots = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep]
.StepParameter["SlotSelection"].ToString();
if (string.IsNullOrEmpty(strSots))
{
return false;
}
string[] bufferSlots = strSots.Split(',');
for (int k = 0; k < bufferSlots.Length; k++)
{
if (Int32.TryParse(bufferSlots[k], out int bufferSlot))
{
if (WaferManager.Instance.CheckNoTray(ModuleName.Buffer, bufferSlot - 1))
{
return true;
}
}
}
}
else if (WaferManager.Instance.CheckNoTray(lstModuleName[j], 0))
{
return true;
}
}
}
return false;
}
}
/// <summary>
/// 判断Wafer的步骤是否都完成了
/// </summary>
/// <param name="waferModule"></param>
/// <param name="waferSlot"></param>
/// <returns></returns>
public virtual bool CheckWaferSequenceStepDone(int slot)
{
lock (SyncRoot)
{
WaferInfo wafer = WaferManager.Instance.GetWafer(Module, slot);
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)
{
lock (SyncRoot)
{
WaferInfo wafer = WaferManager.Instance.GetWafer(Module, waferSlot);
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;
if (processIn != ModuleName.System && !wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep]
.StepModules.Contains(processIn))
return false;
bool hasPm = 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))
{
hasPm = true;
break;
}
}
if (hasPm)
break;
}
if (processIn == ModuleName.System && !hasPm)
return false;
return true;
}
}
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;
// }
// }
//}
return false;
}
}
public virtual bool IsReadyForPick(ModuleName robot, int slot)
{
lock (SyncRoot)
{
return true;
}
}
public virtual bool IsReadyForPlace(ModuleName robot, int slot)
{
lock (SyncRoot)
{
return true;
}
}
public virtual bool PrepareTransfer(ModuleName robot, EnumTransferType type, int slot)
{
lock (SyncRoot)
{
return true;
}
}
public virtual bool PostTransfer(ModuleName robot, EnumTransferType type, int slot)
{
lock (SyncRoot)
{
return true;
}
}
public virtual bool Process(string recipeName, bool isCleanRecipe, bool withDummyWafer)
{
lock (SyncRoot)
{
return true;
}
}
public virtual bool Cooling(bool coolingType, int coolingTime)
{
lock (SyncRoot)
{
return true;
}
}
public virtual bool Aligning()
{
lock (SyncRoot)
{
return true;
}
}
public virtual bool WarmUp(int warmUpTime)
{
lock (SyncRoot)
{
return true;
}
}
public virtual bool CheckWaferTraySeparated()
{
lock (SyncRoot)
{
return true;
}
}
public virtual bool CheckWaferTrayGrouped()
{
lock (SyncRoot)
{
return true;
}
}
public virtual bool CheckSlitValveClosed() //检查闸板阀是否关闭
{
lock (SyncRoot)
{
return true;
}
}
}
}