Sic10/SicRT/Equipments/AutoTransfer.cs

2356 lines
86 KiB
C#
Raw Permalink 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 System.Linq;
using Aitex.Core.Common;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Key;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using Aitex.Sorter.Common;
using Kxware.Common;
using MECF.Framework.Common.DBCore;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.Gem;
using MECF.Framework.Common.Jobs;
using MECF.Framework.Common.Schedulers;
using MECF.Framework.Common.SubstrateTrackings;
using SicRT.Equipments.Schedulers;
using SicRT.Modules.Schedulers;
namespace SicRT.Modules
{
public partial class AutoTransfer : SchedulerModuleFactory
{
private List<ControlJobInfo> _controlJobList = new();
private List<ProcessJobInfo> _processJobList = new();
private int _maxTrayCount = 4; //可以同时运行的石墨盘总数
private const string LogSource = "Scheduler";
private SchedulerDBCallback _dbCallback = new();
private bool _isCycleMode;
private bool _isATMMode;
private int _cycleSetPoint = 0;
private int _cycledCount = 0;
private int _cycledWafer = 0;
private string _curRecipeName = "";
private string _curSequenceName = "";
private bool _isModuleErrorPrevious;
private bool[] _isPMErrorPrevious = new bool[2];
private double _timeBuffer1 { get; set; }
private double _timeBuffer2 { get; set; }
private double _timeBuffer3 { get; set; }
private double _timeLoad { get; set; }
private Dictionary<string, DateTime> _loadWaferInfo = new();
private Dictionary<string, DateTime> _bufferWaferInfo = new();
private Queue<Action> tmRobotActions = new() { };
private R_TRIG _updateAutoJobLocation = new(); //需要向数据库更新Wafer位置
public AutoTransfer()
{
DATA.Subscribe("Scheduler.IsCycleMode", () => _isCycleMode);
DATA.Subscribe("Scheduler.CycledCount", () => _cycledCount);
DATA.Subscribe("Scheduler.CycleSetPoint", () => _cycleSetPoint);
DATA.Subscribe("Scheduler.RecipeName", () => _curRecipeName);
DATA.Subscribe("Scheduler.SequenceName", () => _curSequenceName);
DATA.Subscribe("Scheduler.TimeBuffer1", () => _timeBuffer1);
DATA.Subscribe("Scheduler.TimeBuffer2", () => _timeBuffer2);
DATA.Subscribe("Scheduler.TimeBuffer3", () => _timeBuffer3);
DATA.Subscribe("Scheduler.TimeLoad", () => _timeLoad);
DATA.Subscribe("LoadLock.LocalJobName", () =>
{
var jb = _controlJobList.Find(x => x.Module == "LoadLock");
if (jb != null)
return jb.Name;
return "";
});
DATA.Subscribe("LoadLock.LocalJobStatus", () =>
{
var jb = _controlJobList.Find(x => x.Module == "LoadLock");
if (jb != null)
return jb.State.ToString();
return "";
});
OP.Subscribe($"{ModuleName.TM}.ResetTask", (string cmd, object[] args) =>
{
_tmRobot.ResetTask();
return true;
});
OP.Subscribe($"{ModuleName.EFEM}.ResetTask", (string cmd, object[] args) =>
{
_waferRobot.ResetTask();
_trayRobot.ResetTask();
return true;
});
OP.Subscribe($"{ModuleName.WaferRobot}.ResetTask", (string cmd, object[] args) =>
{
_waferRobot.ResetTask();
return true;
});
OP.Subscribe($"{ModuleName.TrayRobot}.ResetTask", (string cmd, object[] args) =>
{
_trayRobot.ResetTask();
return true;
});
tmRobotActions.Enqueue(MonitorTmRobotLoadPlaceTask);
tmRobotActions.Enqueue(MonitorTmRobotLoadPickTask);
tmRobotActions.Enqueue(MonitorTmRobotPMPlaceTask);
tmRobotActions.Enqueue(MonitorTmRobotPMPickTask);
tmRobotActions.Enqueue(MonitorTmRobotBufferPlaceTask);
tmRobotActions.Enqueue(MonitorTmRobotBufferPickTask);
}
public bool HasJobRunning
{
get { return _controlJobList.Count > 0; }
}
public void Clear()
{
_tmRobot.ResetTask();
foreach (var pm in _lstPms)
{
pm.ResetTask();
}
_load.ResetTask();
_buffer.ResetTask();
_controlJobList.Clear();
_processJobList.Clear();
_loadWaferInfo.Clear();
}
public void ResetTask()
{
if (!_load.IsOnline)
{
_load.ResetTask();
}
if (!_buffer.IsOnline)
{
_buffer.ResetTask();
}
if (!_tmRobot.IsOnline)
{
_tmRobot.ResetTask();
}
foreach (var pm in _lstPms)
{
if (!pm.IsOnline)
{
pm.ResetTask();
}
}
}
#region Job Management
public bool CreateJob(Dictionary<string, object> param)
{
var reason = "";
var slotSequence = (string[])param["SlotSequence"];
var jobId = (string)param["JobId"];
var module = (string)param["Module"];
var lotId = (string)param["LotId"];
////检查Load腔Lock是否锁定
//if(!_load.CheckLocked())
//{
// EV.PostWarningLog(LogSource, $"The Load is Unlocked,do not start");
// return false;
//}
//检查所有Module里Tray的数量
if(GetCurrentTrayCount() >= _maxTrayCount)
{
EV.PostWarningLog(LogSource, $"The machine has more than {_maxTrayCount} Tray");
return false;
}
if (slotSequence.Length != 1)
{
reason = $"slot sequence parameter not valid, length is {slotSequence.Length}, should be 1";
EV.PostWarningLog(LogSource, reason);
return false;
}
//拿到Recipe和ModuleName
var recipeName = "";
var pmModule = ModuleName.System;
var seq = SequenceInfoHelper.GetInfo(slotSequence[0]);
for (var i = 0; i < seq.Steps.Count; i++)
{
var stepInfo = seq.Steps[i];
foreach (var m in stepInfo.StepModules)
{
if (ModuleHelper.IsPm(m))
{
recipeName = seq.Steps[i].RecipeName;
pmModule = m;
}
}
}
//每个PM腔不能超过2个对应Wafer
if(pmModule != ModuleName.System)
{
if (GetRunWaferCount(pmModule) >= _maxTrayCount/2)
{
EV.PostWarningLog(LogSource, $"Creating the job failed . There are already {_maxTrayCount / 2} job of the same pm in the system.");
return false;
}
}
if (CheckModuleHaveWaferWithNoJob(out reason))
{
EV.PostWarningLog(LogSource, $"{reason}");
return false;
}
if (!ValidateSequence(slotSequence, out reason))
{
EV.PostWarningLog(LogSource, $"{reason}");
return false;
}
if (string.IsNullOrEmpty(jobId))
{
jobId = "CJ_Local_Load_" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
if (!string.IsNullOrEmpty(lotId))
{
if (_controlJobList.Exists(x => x.LotName == lotId))
{
reason = $"LotID : {lotId} already created";
EV.PostWarningLog(LogSource, reason);
return false;
}
}
var cj = new ControlJobInfo();
cj.Name = jobId;
cj.Module = module;
cj.LotName = lotId;
cj.LotInnerId = Guid.NewGuid();
cj.LotWafers = new List<WaferInfoRt>();
cj.SetState(EnumControlJobState.WaitingForStart);
List<string> sequenceNameList = new List<string>();
string WaferAssociationInfo = $"WaferAssociationInfo({module}):";
for (int i = 0; i < 1; i++)
{
//检查是否设置Sequence
string sequenceName = slotSequence[i];
if (string.IsNullOrEmpty(sequenceName))
{
reason = $"sequence name is empty";
EV.PostWarningLog(LogSource, reason);
return false;
}
//检查是否有Normal Wafer
if (!WaferManager.Instance.CheckWafer(ModuleHelper.Converter(module), i, WaferStatus.Normal))
{
reason = $"{module} has no normal wafer";
EV.PostWarningLog(LogSource, reason);
return false;
}
WaferInfoRt wafer = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i);
if (wafer.ProcessState != WaferProcessStatus.Idle)
{
reason = $"specifies wafer: {module} slot {i + 1} process state is not idle";
EV.PostWarningLog(LogSource, reason);
return false;
}
if (wafer.ProcessJob != null)
{
reason = $"{module} wafer has processJob";
EV.PostWarningLog(LogSource, reason);
return false;
}
WaferAssociationInfo = WaferAssociationInfo + string.Format(" slot{0} -- {1};", i + 1, slotSequence[i]);
wafer.NextSequenceStep = 0;
wafer.PPID = sequenceName;
wafer.LotId = lotId;
cj.LotWafers.Add(wafer);
_isATMMode = SC.GetValue<bool>("System.IsATMMode");
_isCycleMode = SC.GetValue<bool>("System.IsCycleMode");
//没有包含sequenceName,需新建
if (!sequenceNameList.Exists(s => s == sequenceName))
{
sequenceNameList.Add(sequenceName);
ProcessJobInfo pj = new ProcessJobInfo();
pj.Name = jobId + "_" + (i + 1);
pj.ControlJobName = cj.Name;
pj.Sequence = SequenceInfoHelper.GetInfo(sequenceName);
pj.SetState(EnumProcessJobState.Queued);
pj.SlotWafers = [Tuple.Create(ModuleHelper.Converter(module), i)];
//不是CycleMode模式则CycleCount设为1
pj.CycleCount = _isATMMode && _isCycleMode ? SC.GetValue<int>("System.CycleCount") : 1;
pj.CycleTime = 0;
//检查Sequence对应的PM腔状态
if (!CheckPMState(sequenceName))
{
return false;
}
wafer.ProcessJob = pj;
_processJobList.Add(pj);
cj.ProcessJobNameList.Add(pj.Name);
}
//已包含sequenceName
else
{
ProcessJobInfo pj = _processJobList.Find(p => p.Sequence.Name == sequenceName);
wafer.ProcessJob = pj;
pj.SlotWafers.Add(Tuple.Create(ModuleHelper.Converter(module), i));
}
}
_controlJobList.Add(cj);
int totalWafer = 0;
foreach (string pjName in cj.ProcessJobNameList)
{
ProcessJobInfo tempPJ = _processJobList.First(p => p.Name == pjName);
foreach (var pjSlotWafer in tempPJ.SlotWafers)
{
var wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
WaferDataRecorder.SetCjInfo(wafer.WaferInnerID.ToString(), cj.InnerId.ToString());
WaferDataRecorder.SetWaferSequence(wafer.WaferInnerID.ToString(), tempPJ.Sequence.Name);
WaferDataRecorder.SetWaferLotId(wafer.WaferInnerID.ToString(), jobId);
WaferManager.Instance.UpdateWaferLotId(pjSlotWafer.Item1, pjSlotWafer.Item2, jobId);
totalWafer++;
}
}
CarrierManager.Instance.DeleteCarrier(cj.Module);
CarrierManager.Instance.CreateCarrier(cj.Module);
CarrierManager.Instance.UpdateCarrierId(cj.Module, $"{cj.Module} {DateTime.Now}");
//此carrier为null
CarrierInfo carrier = CarrierManager.Instance.GetCarrier(cj.Module);
JobDataRecorder.StartCJ(cj.InnerId.ToString(), "", cj.Name, cj.Module, cj.Module, totalWafer);
EV.PostInfoLog(LogSource, WaferAssociationInfo);
//保存信息
var waferInfo = WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0);
if (waferInfo != null)
{
waferInfo.LotId = cj.LotName;
if (recipeName.IndexOf(@"\") > 0)
{
recipeName = recipeName.Substring(recipeName.LastIndexOf(@"\") + 1);
}
AutoJobRecorder.Add(waferInfo.WaferID.ToString(), recipeName, cj.LotName, ModuleName.LoadLock.ToString(), GetWaferStatue(waferInfo));
}
return true;
}
public void StartJob(string jobName)
{
_maxTrayCount = _lstPms.Count * 2;
var cj = _controlJobList.Find(x => x.Name == jobName);
if (cj == null)
{
EV.PostWarningLog(LogSource, $"start job rejected, not found job with id {jobName}");
return;
}
if (cj.State == EnumControlJobState.WaitingForStart)
{
cj.BeginTime = DateTime.Now;
cj.LotInnerId = Guid.NewGuid();
//_dbCallback.LotCreated(cj);
foreach (var pjName in cj.ProcessJobNameList)
{
var pj = _processJobList.Find(x => x.Name == pjName);
if (pj == null)
{
LOG.Error($"Not find pj named {pjName} in {cj.Name}");
continue;
}
if (pj.State == EnumProcessJobState.Queued)
{
ActiveProcessJob(pj);
}
}
cj.SetState(EnumControlJobState.Executing);
string squenceID = cj.LotWafers != null ? cj.LotWafers[0].PPID : string.Empty;
//补全路径
squenceID = $"Sequence\\{squenceID}.seq";
GemManager.Instance.Equipment?.TriggerEvent("JobStart", new string[] { "LotID", "SequenceID" }, new object[] { cj.LotName, squenceID });
}
}
private string GetWaferStatue(WaferInfoRt wafer)
{
if (wafer.ProcessState == WaferProcessStatus.InProcess)
{
return "InProcess";
}
else if (wafer.ProcessState == WaferProcessStatus.Completed)
{
return "Completed";
}
else
{
return "Idle";
}
}
private bool ValidateSequence(string[] seqs, out string reason)
{
reason = string.Empty;
//bool isAllSequenceNull = true;
//for (int i = 0; i < seqs.Length; i++)
//{
// if (string.IsNullOrEmpty(seqs[i]))
// continue;
// var sequence = SequenceInfoHelper.GetInfo(seqs[i]);
// if ((sequence == null || sequence.Steps == null || sequence.Steps.Count == 0) && !string.IsNullOrEmpty(sequence.Name))
// {
// reason = $"Invalid sequence {seqs[i]}";
// return false;
// }
// isAllSequenceNull = false;
// if (sequence.Steps != null)
// {
// int currentIndex = 0;
// if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.Aligner)
// {
// reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Aligner";
// return false;
// }
// else
// {
// if (sequence.Steps[currentIndex].AlignAngle < 0 || sequence.Steps[currentIndex].AlignAngle > 360)
// {
// reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Aligner angle parameter is not valid";
// return false;
// }
// }
// currentIndex++;
// if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.Load)
// {
// reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Load";
// return false;
// }
// currentIndex++;
// if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.Buffer)
// {
// reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Buffer";
// return false;
// }
// else
// {
// //if (!sequence.Steps[currentIndex].StepParameter.ContainsKey("SlotSelection")
// // || string.IsNullOrEmpty(sequence.Steps[currentIndex].StepParameter["SlotSelection"].ToString())
// // || sequence.Steps[currentIndex].StepParameter["SlotSelection"].ToString().Contains("3"))
// //{
// // reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Buffer SlotSelection parameter is not valid";
// // return false;
// //}
// if (!sequence.Steps[currentIndex].StepParameter.ContainsKey("BufferType") || !sequence.Steps[currentIndex].StepParameter["BufferType"].ToString().Contains("Heat"))
// {
// reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Buffer BufferType parameter is not valid";
// return false;
// }
// }
// currentIndex++;
// if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules.Any(pm => !ModuleHelper.IsPm(pm)))
// {
// reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be PM";
// return false;
// }
// //if (sequence.Steps.Count == 7)
// //{
// // currentIndex++;
// // if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.Buffer)
// // {
// // reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Buffer";
// // return false;
// // }
// // else
// // {
// // if (!sequence.Steps[currentIndex].StepParameter.ContainsKey("SlotSelection")
// // || sequence.Steps[currentIndex].StepParameter["SlotSelection"].ToString() != "3")
// // {
// // reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Buffer SlotSelection parameter is not valid";
// // return false;
// // }
// // if (!sequence.Steps[currentIndex].StepParameter.ContainsKey("BufferType") || !sequence.Steps[currentIndex].StepParameter["BufferType"].ToString().Contains("Cooling"))
// // {
// // reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Buffer BufferType parameter is not valid";
// // return false;
// // }
// // }
// //}
// currentIndex++;
// if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.UnLoad)
// {
// reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Unload";
// return false;
// }
// currentIndex++;
// if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.Aligner)
// {
// reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Aligner";
// return false;
// }
// else
// {
// if (sequence.Steps[0].AlignAngle < 0 || sequence.Steps[0].AlignAngle > 360)
// {
// reason = $"Invalid sequence {seqs[i]}, Aligner angle parameter is not valid";
// return false;
// }
// }
// }
//}
//if (isAllSequenceNull)
//{
// reason = $"Invalid sequence, sequence are all null ";
// return false;
//}
return true;
}
internal void StopJob(string jobName)
{
//ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
//if (cj == null)
//{
// EV.PostWarningLog(LogSource, $"stop job rejected, not found job with id {jobName}");
// return;
//}
foreach (var cj in _controlJobList)
{
foreach (var pj in _processJobList)
{
if (pj.ControlJobName == cj.Name)
{
pj.SetState(EnumProcessJobState.Stopping);
}
}
if (_cycleSetPoint > 0)
{
_cycleSetPoint = _cycledCount;
}
}
}
public void Abort()
{
try
{
var wafer = WaferManager.Instance.GetWafer(ModuleName.PM1, 0);
if (wafer != null && !string.IsNullOrEmpty(wafer.WaferID))
{
AutoJobRecorder.UpdatePosition(wafer.WaferID.ToString(), ModuleName.PM1.ToString(), "Abort");
}
var wafer1 = WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0);
if (wafer1 != null && !string.IsNullOrEmpty(wafer1.WaferID))
{
AutoJobRecorder.UpdatePosition(wafer1.WaferID.ToString(), ModuleName.TM.ToString(), "Abort");
}
var wafer2 = WaferManager.Instance.GetWafer(ModuleName.Buffer, 0);
if (wafer2 != null && !string.IsNullOrEmpty(wafer2.WaferID))
{
AutoJobRecorder.UpdatePosition(wafer2.WaferID.ToString(), ModuleName.Buffer.ToString(), "Abort");
}
var wafer3 = WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0);
if (wafer3 != null && !string.IsNullOrEmpty(wafer3.WaferID))
{
AutoJobRecorder.UpdatePosition(wafer3.WaferID.ToString(), ModuleName.LoadLock.ToString(), "Abort");
}
var cjList = _controlJobList.FindAll(c => c.State == EnumControlJobState.Executing);
if (cjList != null)
{
foreach (var cj in cjList)
{
string squenceID = cj.LotWafers != null ? cj.LotWafers[0].PPID : string.Empty;
//补全路径
squenceID = $"Sequence\\{squenceID}.seq";
GemManager.Instance.Equipment?.TriggerEvent("JobAbort", new string[] { "LotID", "SequenceID" }, new object[] { cj.LotName, squenceID });
}
}
}
catch (Exception ex)
{
LOG.Error(ex.Message, ex);
}
}
internal void AbortJob(string jobName)
{
var cj = _controlJobList.Find(x => x.Name == jobName);
if (cj == null)
{
EV.PostWarningLog(LogSource, $"abort job rejected, not found job with id {jobName}");
return;
}
var unprocessed_cj = 0;
var aborted_cj = 0;
var pjAbortList = new List<ProcessJobInfo>();
foreach (var pj in _processJobList)
{
if (pj.ControlJobName == cj.Name)
{
pj.SetState(EnumProcessJobState.Aborting);
pjAbortList.Add(pj);
var unprocessed = 0;
var aborted = 0;
var wafers = WaferManager.Instance.GetWaferByProcessJob(pj.Name);
foreach (var waferInfo in wafers)
{
waferInfo.ProcessJob = null;
waferInfo.NextSequenceStep = 0;
if (waferInfo.ProcessState != WaferProcessStatus.Completed)
{
unprocessed++;
unprocessed_cj++;
}
}
JobDataRecorder.EndPJ(pj.InnerId.ToString(), aborted, unprocessed);
}
}
foreach (var pj in pjAbortList)
{
_processJobList.Remove(pj);
}
_controlJobList.Remove(cj);
_dbCallback.LotFinished(cj);
JobDataRecorder.EndCJ(cj.InnerId.ToString(), aborted_cj, unprocessed_cj);
}
public void ResumeJob(string jobName)
{
//ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
//if (cj == null)
//{
// EV.PostWarningLog(LogSource, $"resume job rejected, not found job with id {jobName}");
// return;
//}
foreach (var cj in _controlJobList)
{
if (cj.State == EnumControlJobState.Paused)
{
cj.SetState(EnumControlJobState.Executing);
}
}
}
internal void PauseJob(string jobName)
{
//ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
//if (cj == null)
//{
// EV.PostWarningLog(LogSource, $"pause job rejected, not found job with id {jobName}");
// return;
//}
foreach (var cj in _controlJobList)
{
if (cj.State == EnumControlJobState.Executing)
{
cj.SetState(EnumControlJobState.Paused);
}
}
}
internal bool CheckPMState(string sequence)
{
var seqInfo = SequenceInfoHelper.GetInfo(sequence);
if (seqInfo.Name != "")
{
foreach (var step in seqInfo.Steps)
{
foreach (var moduleName in step.StepModules)
{
if (ModuleHelper.IsPm(moduleName))
{
var module = _lstPms.Find(x => x.Module == moduleName);
if (module != null)
{
if (module.IsError)
{
EV.PostWarningLog("Scheduler", $"{moduleName} is not be error");
return false;
}
if (!module.IsOnline)
{
EV.PostWarningLog("Scheduler", $"{moduleName} is not be Online");
return false;
}
if (!module.IsLineHeaterEnable)
{
EV.PostWarningLog("Scheduler", $"{moduleName} LineHeater is not be Open");
return false;
}
//if (module.IsService)
//{
// EV.PostWarningLog("Scheduler", $"can not start job, {moduleName} is Service Mode");
// return false;
//}
}
else
{
EV.PostWarningLog("Scheduler", "Sequence PM can not be null!");
return false;
}
}
}
}
}
else
{
EV.PostWarningLog("Scheduler", "Sequence can not be null!");
return false;
}
return true;
}
#endregion
/// <summary>
/// Start Auto Transfer
/// </summary>
/// <param name="objs"></param>
/// <returns></returns>
public Result CheckAutoMode(params object[] objs)
{
if (!_tmRobot.IsOnline || _tmRobot.IsError)
{
EV.PostWarningLog("Scheduler", "can not change to auto mode, TM robot should be online and no error");
return Result.FAIL;
}
return Result.RUN;
}
public Result Monitor()
{
MonitorModuleTasks();
MonitorAutoJobStatus();
MonitorModuleError();
MonitorJobTasks();
return Result.RUN;
}
#region Job task
public Result MonitorJobTasks()
{
UpdateProcessJobStatus();
UpdateControlJobStatus();
return Result.RUN;
}
/// <summary>
/// 检查PJ中的Wafer信息是否被清空。
/// <para>如果被清空则说明中间过程中Wafer被人工删除此时返回true通知相关Monitor可以改PJ。</para>
/// </summary>
/// <param name="pj"></param>
/// <returns></returns>
protected bool CheckAllWaferDeleted(ProcessJobInfo pj)
{
var wi = WaferManager.Instance.GetWaferByProcessJob(pj.Name);
return wi == null || wi.Length <= 0;
}
protected bool CheckAllWaferReturned(ProcessJobInfo pj, bool checkAllProcessed)
{
for (var i = 0; i < pj.SlotWafers.Count; ++i)
{
WaferInfoRt wafer = WaferManager.Instance.GetWafer(pj.SlotWafers[i].Item1, pj.SlotWafers[i].Item2);
if (wafer.IsWaferEmpty)
return false;
if (checkAllProcessed && CheckWaferNeedProcess(pj.SlotWafers[i].Item1, pj.SlotWafers[i].Item2))
return false;
if (wafer.ProcessJob == null || wafer.ProcessJob.InnerId != pj.InnerId)
{
return false;
}
}
return true;
}
protected bool CheckAllDummyWaferReturned()
{
foreach (var schedulerPm in _lstPms)
{
if (WaferManager.Instance.CheckWaferIsDummy(schedulerPm.Module, 0))
return false;
}
if (WaferManager.Instance.CheckWaferIsDummy(_tmRobot.Module, 0))
return false;
if (WaferManager.Instance.CheckWaferIsDummy(_tmRobot.Module, 1))
return false;
return true;
}
protected bool CheckAllPmCleaned(ProcessJobInfo pj)
{
foreach (var schedulerPm in _lstPms)
{
if (GetModule(schedulerPm.Module).CheckNeedRunClean(out _, out _))
{
foreach (var sequenceStepInfo in pj.Sequence.Steps)
{
if (sequenceStepInfo.StepModules.Contains(schedulerPm.Module))
return false;
}
}
}
return true;
}
private void UpdateProcessJobStatus()
{
foreach (var pj in _processJobList)
{
if (pj.State == EnumProcessJobState.Processing)
{
if (CheckAllWaferReturned(pj, true))
{
if (CheckWaferSequenceStepDone(ModuleName.LoadLock, 0))
{
pj.CycleTime++;
if (pj.CycleTime < pj.CycleCount)
{
//重新设置wafer
for (int i = 0; i < pj.SlotWafers.Count; ++i)
{
var wafer = GetModule(pj.SlotWafers[i].Item1).GetWaferInfo(pj.SlotWafers[i].Item2);
wafer.NextSequenceStep = 0;
wafer.WaferStatus = WaferStatus.Normal;
wafer.ProcessState = WaferProcessStatus.Idle;
}
}
else
{
_load.SetJobStatue();
pj.SetState(EnumProcessJobState.ProcessingComplete);
JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0);
AutoJobRecorder.EndJob(WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0).WaferID.ToString());
}
}
}
if (CheckAllWaferDeleted(pj))
{
_load.SetJobStatue();
pj.SetState(EnumProcessJobState.Complete);
JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0);
AutoJobRecorder.EndJob(WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0).WaferID.ToString());
}
}
else if (pj.State == EnumProcessJobState.Stopping)
{
if (CheckAllWaferReturned(pj, false))
{
if (CheckWaferSequenceStepDone(ModuleName.LoadLock, 0))
{
_load.SetJobStatue();
pj.SetState(EnumProcessJobState.Complete);
JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0);
AutoJobRecorder.EndJob(WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0).WaferID.ToString());
}
}
}
}
}
private void UpdateControlJobStatus()
{
try
{
if (_controlJobList.Count == 0)
{
return;
}
foreach (var cj in _controlJobList)
{
if (cj.State == EnumControlJobState.Executing)
{
bool allPjCompleted = true;
foreach (var pjName in cj.ProcessJobNameList)
{
var pj = _processJobList.Find(x => x.Name == pjName);
if (pj != null)
{
if (pj.State != EnumProcessJobState.ProcessingComplete && pj.State != EnumProcessJobState.Complete)
{
allPjCompleted = false;
break;
}
}
}
if (allPjCompleted)
{
cj.SetState(EnumControlJobState.Completed);
foreach (var pjName in cj.ProcessJobNameList)
{
var pj = _processJobList.Find(x => x.Name == pjName);
if (pj != null)
{
_processJobList.Remove(pj);
}
}
JobDataRecorder.EndCJ(cj.InnerId.ToString(), 0, 0);
_dbCallback.LotFinished(cj);
}
}
}
for (int i = 0; i < _controlJobList.Count; i++)
{
if (_controlJobList[i].State == EnumControlJobState.Completed)
{
_controlJobList.RemoveAt(i);
}
}
}
catch (Exception ex)
{
LOG.Error(ex.Message,ex);
}
}
public void MonitorAutoJobStatus()
{
try
{
_updateAutoJobLocation.CLK = _tmRobot.IsAvailable;
if (_updateAutoJobLocation.Q)
{
WaferInfoRt wafer = WaferManager.Instance.GetWafer(ModuleName.PM1, 0);
if (wafer != null && !string.IsNullOrEmpty(wafer.WaferID))
{
AutoJobRecorder.UpdatePosition(wafer.WaferID.ToString(), ModuleName.PM1.ToString(), GetWaferStatue(wafer));
}
WaferInfoRt wafer1 = WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0);
if (wafer1 != null && !string.IsNullOrEmpty(wafer1.WaferID))
{
AutoJobRecorder.UpdatePosition(wafer1.WaferID.ToString(), ModuleName.TM.ToString(), GetWaferStatue(wafer1));
}
WaferInfoRt wafer2 = WaferManager.Instance.GetWafer(ModuleName.Buffer, 0);
if (wafer2 != null && !string.IsNullOrEmpty(wafer2.WaferID))
{
AutoJobRecorder.UpdatePosition(wafer2.WaferID.ToString(), ModuleName.Buffer.ToString(), GetWaferStatue(wafer2));
}
WaferInfoRt wafer3 = WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0);
if (wafer3 != null && !string.IsNullOrEmpty(wafer3.WaferID))
{
AutoJobRecorder.UpdatePosition(wafer3.WaferID.ToString(), ModuleName.LoadLock.ToString(), GetWaferStatue(wafer3));
}
}
}
catch (Exception ex)
{
LOG.Error(ex.Message, ex);
}
}
public bool CheckAllJobDone()
{
//条件满足状态由AutoRunning切换到AutoIdle状态
if (_load.IsAvailable && _tmRobot.IsAvailable && _tmRobot.NoWafer(0) && _tmRobot.NoTray(0) &&
_buffer.NoWafer(0) && _buffer.NoTray(0) && _buffer.NoWafer(1) && _buffer.NoTray(1) && _buffer.NoWafer(2) && _buffer.NoTray(2) &&
_pm1.NoWafer(0) && _pm1.NoTray(0) && _pm2.NoWafer(0) && _pm2.NoTray(0) && !_controlJobList.Exists(c => c.State == EnumControlJobState.Executing))
{
return true;
}
return false;
}
private bool ActiveProcessJob(ProcessJobInfo pj)
{
foreach (var pjSlotWafer in pj.SlotWafers)
{
WaferInfoRt wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(pjSlotWafer.Item2);
wafer.ProcessJob = pj;
wafer.NextSequenceStep = 0;
WaferDataRecorder.SetPjInfo(wafer.WaferInnerID.ToString(), pj.InnerId.ToString());
}
var cj = _controlJobList.Find(x => x.Name == pj.ControlJobName);
var carrier = CarrierManager.Instance.GetCarrier(cj.Module);
JobDataRecorder.StartPJ(pj.InnerId.ToString(), null, cj.InnerId.ToString(), pj.Name, cj.Module, cj.Module, pj.SlotWafers.Count);
pj.SetState(EnumProcessJobState.Processing);
return true;
}
#endregion
#region Module task
public Result MonitorModuleTasks()
{
MonitorPMTask();
MonitorBufferTask();
MonitorTmRobotTask();
MonitorLoadTask();
return Result.RUN;
}
private void MonitorBufferTask()
{
if (!_buffer.IsAvailable)
{
return;
}
for (var i = 0; i < 3; i++)
{
var canExcute = _buffer.HasWafer(i) && _buffer.CheckWaferNextStepIsThis(_buffer.Module, i);
if (canExcute)
{
WaferInfoRt bufferWafer = _buffer.GetWaferInfo(i);
if(i == 2 || i ==1)
{
bufferWafer.NextSequenceStep++;
return;
}
var bufferSetValue = 0;
if (!GetWaferSequenceNextValue(ModuleName.Buffer, i, "Type", out var strBufferType))
{
continue;
}
if (!GetWaferSequenceNextValue(ModuleName.Buffer, i, "SetValue", out var strBufferSetValue))
{
continue;
}
if (!Int32.TryParse(strBufferSetValue, out bufferSetValue))
{
continue;
}
//分别判断冷却和加热方式温度是否达到
if (strBufferType == "HeatByTemp")
{
if (_bufferWaferInfo.ContainsKey(bufferWafer.WaferInnerID.ToString()))
{
var dtStartTime = _bufferWaferInfo[bufferWafer.WaferInnerID.ToString()];
var pastTime = (DateTime.Now - dtStartTime).TotalSeconds;
//选择By温度5秒后再判断温度
if (pastTime > 5)
{
if (_buffer.GetTemperature() >= bufferSetValue)
bufferWafer.NextSequenceStep++;
_bufferWaferInfo.Remove(bufferWafer.WaferInnerID.ToString());
}
}
else
{
_bufferWaferInfo.Add(bufferWafer.WaferInnerID.ToString(), DateTime.Now);
}
}
else if (strBufferType == "HeatByTime")
{
if (_bufferWaferInfo.ContainsKey(bufferWafer.WaferInnerID.ToString()))
{
var dtStartTime = _bufferWaferInfo[bufferWafer.WaferInnerID.ToString()];
var pastTime = (DateTime.Now - dtStartTime).TotalSeconds;
if (i == 0)
{
_timeBuffer1 = pastTime > bufferSetValue ? 0 : (bufferSetValue - pastTime);
}
else if (i == 1)
{
_timeBuffer2 = pastTime > bufferSetValue ? 0 : (bufferSetValue - pastTime);
}
else if (i == 2)
{
_timeBuffer3 = pastTime > bufferSetValue ? 0 : (bufferSetValue - pastTime);
}
if (pastTime > bufferSetValue)
{
bufferWafer.NextSequenceStep++;
_bufferWaferInfo.Remove(bufferWafer.WaferInnerID.ToString());
}
}
else
{
_bufferWaferInfo.Add(bufferWafer.WaferInnerID.ToString(), DateTime.Now);
}
}
else if (strBufferType == "CoolingByTime")
{
if (_bufferWaferInfo.ContainsKey(bufferWafer.WaferInnerID.ToString()))
{
var dtStartTime = _bufferWaferInfo[bufferWafer.WaferInnerID.ToString()];
var pastTime = (DateTime.Now - dtStartTime).TotalSeconds;
if (i == 0)
{
_timeBuffer1 = pastTime > bufferSetValue ? 0 : (bufferSetValue - pastTime);
}
else if (i == 1)
{
_timeBuffer2 = pastTime > bufferSetValue ? 0 : (bufferSetValue - pastTime);
}
else if (i == 2)
{
_timeBuffer3 = pastTime > bufferSetValue ? 0 : (bufferSetValue - pastTime);
}
if (pastTime > bufferSetValue)
{
bufferWafer.NextSequenceStep++;
_bufferWaferInfo.Remove(bufferWafer.WaferInnerID.ToString());
}
}
else
{
_bufferWaferInfo.Add(bufferWafer.WaferInnerID.ToString(), DateTime.Now);
}
}
return;
}
}
//Place和Pick条件都一样
if (!_buffer.IsReadyForPlace(ModuleName.TMRobot, 0))
{
_buffer.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0);
}
}
/// <summary>
/// 检测到LL中的Wafer已完成Job。
/// </summary>
//private readonly R_TRIG _trigLLPjDone = new();
private void MonitorLoadTask()
{
if (!_load.IsAvailable)
{
return;
}
if (_load.FirstDetectWaferArrive(0) || _load.FirstDetectWaferLeave(0))
{
_load.ResetPurged();
//_trigLLPjDone.RST = true;
}
var canExcute = _load.HasWafer(0);
if (canExcute)
{
if (_load.GetWaferInfo(0).ProcessJob != null)
{
if (_load.GetWaferInfo(0).ProcessJob.State != EnumProcessJobState.Processing)
{
return;
}
}
else
{
return;
}
if (!_load.CheckWaferSequenceStepDone(0))
{
if (_load.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0))
{
if (_load.CheckWaferNeedProcess(0))
{
_load.Purge(_load.GetWaferPurgeCount(0), _load.GetWaferPumpDelayTime(0));
_load.GetWaferInfo(0).NextSequenceStep++;
return;
}
else
{
if (!GetWaferSequenceNextValue(ModuleName.Load, 0, "Type", out var strType))
{
return;
}
if (!GetWaferSequenceNextValue(ModuleName.Load, 0, "SetValue", out var strSetValue))
{
return;
}
if (!Int32.TryParse(strSetValue, out var setValue))
{
return;
}
//Load腔没有测温
//if (strType == "CoolingByTemp")
//{
// if (_load.GetTemperature() <= setValue)
// {
// _load.Purge(_load.GetWaferPurgeCount(0), _load.GetWaferPumpDelayTime(0));
// _load.Vent();
// _load.GetWaferInfo(0).NextSequenceStep++;
// }
//}
if (strType == "CoolingByTime")
{
if (_loadWaferInfo.ContainsKey(_load.GetWaferInfo(0).WaferInnerID.ToString()))
{
var dtStartTime = _loadWaferInfo[_load.GetWaferInfo(0).WaferInnerID.ToString()];
var pastTime = (DateTime.Now - dtStartTime).TotalSeconds;
_timeLoad = pastTime > setValue ? 0 : (setValue - pastTime);
if (pastTime > setValue)
{
if (!_load.CheckPurged())
{
_load.Purge(_load.GetWaferPurgeCount(0), _load.GetWaferPumpDelayTime(0));
return;
}
_load.ResetPurged();
_load.Vent();
_load.GetWaferInfo(0).NextSequenceStep++;
_loadWaferInfo.Remove(_load.GetWaferInfo(0).WaferInnerID.ToString());
//补全路径
string squenceID = $"Sequence\\{_load.GetWaferInfo(0).PPID}.seq";
GemManager.Instance.Equipment?.TriggerEvent("JobComplete", new string[] { "LotID", "SequenceID" },
new object[] { _load.GetWaferInfo(0).LotId, squenceID });
return;
}
}
else
{
_loadWaferInfo.Add(_load.GetWaferInfo(0).WaferInnerID.ToString(), DateTime.Now);
return;
}
}
}
}
else if (!_load.IsReadyForPick(ModuleName.TMRobot, 0) && !_tmRobot.IsInPumping)
{
_load.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Pick, 0);
return;
}
}
/*else
{
// Job Done, 响蜂鸣器
_trigLLPjDone.CLK = true;
if (_trigLLPjDone.Q)
{
OP.DoOperation("System.AlertJobDone", ModuleName.LoadLock.ToString(), 0);
}
}*/
}
else
{
if (_load.NoTray(0))
{
if (!_load.IsReadyForPlace(ModuleName.TMRobot, 0) && !_tmRobot.IsInPumping)
{
_load.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0);
return;
}
}
}
}
private void MonitorPMTask()
{
//if (_pm1.FirstDetectTrayArrive(0))
//{
// _pm1.GetWaferInfo(0).TrayUsedForWhichPM = (int)_pm1.Module;
//}
//if (_pm2.FirstDetectTrayArrive(1))
//{
// _pm2.GetWaferInfo(0).TrayUsedForWhichPM = (int)_pm2.Module;
//}
foreach (var pm in _lstPms)
{
if (!pm.IsAvailable)
continue;
if (pm.HasWafer(0))
{
if (pm.CheckNeedRunClean(out var withWafer, out var recipe) && withWafer
&& GetModule(pm.Module).GetWaferInfo(0).WaferStatus == WaferStatus.Dummy
&& GetModule(pm.Module).GetWaferInfo(0).ProcessState == WaferProcessStatus.Wait)
{
pm.Process(recipe, true, withWafer);
continue;
}
if (GetModule(pm.Module).CheckWaferNeedProcess(0, pm.Module))
{
WaferInfoRt wafer = GetModule(pm.Module).GetWaferInfo(0);
if (pm.Process(wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].RecipeName, false, true))
{
GetModule(pm.Module).GetWaferInfo(0).NextSequenceStep++;
continue;
}
}
else
{
if (!pm.IsReadyForPick(ModuleName.TMRobot, 0))
{
pm.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Pick, 0);
}
}
}
else
{
if (GetModule(pm.Module).CheckNeedRunClean(out var withWafer, out var recipe) && !withWafer)
{
pm.Process(recipe, true, withWafer);
continue;
}
if (!pm.IsReadyForPlace(ModuleName.TMRobot, 0))
{
pm.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0);
}
}
}
}
private void MonitorTmRobotTask()
{
// TMRobot Idle或者Error时清除被传盘对象的等待状态
if (_tmRobot.CheckTaskDone())
{
foreach (var pm in _lstPms.Where(
pm => pm.IsWaitTransfer(ModuleName.TMRobot) && _tmRobot.CheckTaskDone()))
{
pm.StopWaitTransfer(ModuleName.TMRobot);
}
if (_buffer.IsWaitTransfer(ModuleName.TMRobot) && _tmRobot.CheckTaskDone())
_buffer.StopWaitTransfer(ModuleName.TMRobot);
if (_load.IsWaitTransfer(ModuleName.TMRobot) && _tmRobot.CheckTaskDone())
_load.StopWaitTransfer(ModuleName.TMRobot);
//if (_unload.IsWaitTransfer(ModuleName.TMRobot))
// _unload.StopWaitTransfer(ModuleName.TMRobot);
}
if (!_tmRobot.IsAvailable)
{
return;
}
if (!_tmRobot.IsAvailable)
return;
var act = tmRobotActions.Peek();
act.Invoke();
tmRobotActions.Enqueue(tmRobotActions.Dequeue());
}
#region TmRobotTask
private void MonitorTmRobotLoadPlaceTask()
{
if (!_load.IsAvailable || !_tmRobot.IsAvailable)
{
return;
}
//place Robot有Tray有Wafer,Load无Tray,无Wafer
var canPlace = _tmRobot.HasTray(0) && _load.NoTray(0) && _load.NoWafer(0)
&& !_load.CheckTrayPlaced();
if (canPlace)
{
if(!_tmRobot.CheckWaferNeedProcess(0) || _tmRobot.CheckWaferSequenceStepDone(0) || _load.CheckWaferNextStepIsThis(ModuleName.TMRobot,0))
{
if (_load.IsReadyForPlace(ModuleName.TMRobot, 0))
{
if (_tmRobot.Place(_load.Module, 0, Hand.Blade1))
{
_load.WaitTransfer(ModuleName.TMRobot, false, 0);
return;
}
}
}
}
}
private void MonitorTmRobotLoadPickTask()
{
if (!_load.IsAvailable || !_tmRobot.IsAvailable)
{
return;
}
//pick TM无Tray,需要Process
var canPick = _tmRobot.NoTray(0) && _tmRobot.NoWafer(0)
&& _load.HasTray(0) && _load.HasWafer(0)
&& _load.CheckWaferNeedProcess(0)
&& !_load.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0)
&& _load.CheckWaferNextStepModuleNoTray(0);
if (canPick)
{
//下一步如果去PM1判断PM1是否准备好
if (_pm1.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0))
{
if (!_pm1.IsAvailable || _pm1.HasTray(0) || _pm1.HasWafer(0) || !_pm1.IsReadyForPlace(ModuleName.TMRobot, 0))
{
return;
}
if(!_pm1.CheckBufferToPMTemp())
{
return;
}
}
//下一步如果去PM2判断PM2是否准备好
if (_pm2.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0))
{
if (!_pm2.IsAvailable || _pm2.HasTray(0) || _pm2.HasWafer(0) || !_pm2.IsReadyForPlace(ModuleName.TMRobot, 0))
{
return;
}
if (!_pm2.CheckBufferToPMTemp())
{
return;
}
}
if (_load.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(_load.Module, 0, Hand.Blade1))
{
_load.WaitTransfer(ModuleName.TMRobot, true, 0);
return;
}
}
}
}
private void MonitorTmRobotBufferPlaceTask()
{
if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
{
return;
}
//place Buffer位置没有Tray,Robot有Wafer,下一步骤是Buffer
var canPalce = _tmRobot.HasTray(0);
if (canPalce)
{
SlotItem bufferEmptySlot = null;
if (_tmRobot.CheckWaferNeedProcess(0, _pm1.Module)
&& _buffer.NoTray(2)
&& _buffer.NoWafer(2)
&& _buffer.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0))
{
bufferEmptySlot = new SlotItem(ModuleName.Buffer, 2);
}
else if (_tmRobot.CheckWaferNeedProcess(0, _pm2.Module)
&& _buffer.NoTray(1)
&& _buffer.NoWafer(1)
&& _buffer.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0))
{
bufferEmptySlot = new SlotItem(ModuleName.Buffer, 1);
}
//TMRobot的下一步是Buffer3
else if (!_tmRobot.CheckWaferNeedProcess(0)
&& _buffer.NoTray(0)
&& _buffer.NoWafer(0)
&& _buffer.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0))
{
bufferEmptySlot = new SlotItem(ModuleName.Buffer, 0);
}
//Load里有Tray
else if (!_tmRobot.CheckWaferNeedProcess(0)
&& _buffer.NoTray(0)
&& _buffer.NoWafer(0)
&& _load.HasTray(0))
{
bufferEmptySlot = new SlotItem(ModuleName.Buffer, 0);
}
if (bufferEmptySlot == null)
{
return;
}
if (_buffer.IsReadyForPlace(ModuleName.TMRobot, bufferEmptySlot.Slot))
{
if (_tmRobot.Place(_buffer.Module, bufferEmptySlot.Slot, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
return;
}
}
private void MonitorTmRobotBufferPickTask()
{
if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
{
return;
}
//pick,Buffer有Tray,机械手没有Tray
MonitorTmRobotBuffer1PickTask();
MonitorTmRobotBuffer2PickTask();
MonitorTmRobotBuffer3PickTask();
}
private void MonitorTmRobotBuffer3PickTask()
{
if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
{
return;
}
//pick,Buffer有Tray,机械手没有Tray
var canPick = _tmRobot.NoTray(0);
if (canPick)
{
if (_buffer.HasTray(2) && _buffer.HasWafer(2))
{
if (_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, 2))
{
return;
}
//下一步如果去PM1判断PM1是否准备好
if (_pm1.CheckWaferNextStepIsThis(ModuleName.Buffer, 2))
{
if (!_pm1.IsAvailable || _pm1.HasTray(0) || _pm1.HasWafer(0) || !_pm1.IsReadyForPlace(ModuleName.TMRobot, 0))
{
return;
}
if(!_pm1.CheckBufferToPMTemp())
{
return;
}
}
if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(_buffer.Module, 2, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
}
private void MonitorTmRobotBuffer2PickTask()
{
if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
{
return;
}
//pick,Buffer有Tray,机械手没有Tray
var canPick = _tmRobot.NoTray(0);
if (canPick)
{
if (_buffer.HasTray(1) && _buffer.HasWafer(1))
{
if (_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, 1))
{
return;
}
//下一步如果去PM2判断PM2是否准备好
if (_pm2.CheckWaferNextStepIsThis(ModuleName.Buffer, 1))
{
if (!_pm2.IsAvailable || _pm2.HasTray(0) || _pm2.HasWafer(0) || !_pm2.IsReadyForPlace(ModuleName.TMRobot, 0))
{
return;
}
if(!_pm2.CheckBufferToPMTemp())
{
return;
}
}
if (_buffer.CheckWaferNextStepModuleNoTray(1))
{
if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(_buffer.Module, 1, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
}
}
private void MonitorTmRobotBuffer1PickTask()
{
if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
{
return;
}
var canPick = _tmRobot.NoTray(0) && _tmRobot.NoWafer(0);
if (canPick)
{
if (_buffer.HasTray(0)
&& _load.NoTray(0) && _load.NoWafer(0)
&& !_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, 0)
&& _load.IsReadyForPlace(ModuleName.TMRobot,0)
&& _load.IsAvailable
&& _load.IsOnline)
{
if (!_buffer.CheckWaferNeedProcess(0))
{
if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(_buffer.Module,0, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
}
}
private void MonitorTmRobotPMPlaceTask()
{
if (!_tmRobot.IsAvailable)
return;
//place to pm
var blade0HasWaferAndNeedProcess = _tmRobot.HasWafer(0) && _tmRobot.HasTray(0) && _tmRobot.CheckWaferNeedProcess(0);
if (blade0HasWaferAndNeedProcess)
{
foreach (var pm in _lstPms)
{
if (!pm.IsAvailable
|| !GetModule(pm.Module).NoWafer(0)
|| !GetModule(pm.Module).NoTray(0)
|| !pm.IsReadyForPlace(ModuleName.TMRobot, 0))
continue;
var blade0Place = _tmRobot.HasWafer(0) && _tmRobot.CheckWaferNeedProcess(0, pm.Module) &&
pm.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0);
if (blade0Place)
{
if (!pm.CheckBufferToPMTemp())
{
continue;
}
if (_tmRobot.Place(pm.Module, 0, Hand.Blade1))
{
pm.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
}
private void MonitorTmRobotPMPickTask()
{
if (!_tmRobot.IsAvailable)
return;
//TMRobot从PM取Wafer,Buffer1中不能有Tray,否则先去Buffer1中的Tray
if (_tmRobot.NoWafer(0) && _tmRobot.NoTray(0))
{
var pickBlade = Hand.Blade1;
var pickPm = ModuleName.System;
foreach (var schedulerPm in _lstPms)
{
//增加温度低于900才能Pick的限制
if (!schedulerPm.IsAvailable
|| GetModule(schedulerPm.Module).NoTray(0)
|| GetModule(schedulerPm.Module).CheckWaferNeedProcess(0, schedulerPm.Module)
|| _tmRobot.HasWafer((int)pickBlade)
|| _tmRobot.HasTray((int)pickBlade))
continue;
if(!schedulerPm.CheckPMToTMRobotTemp())
{
continue;
}
//如果下一步是Buffer,只能取出放Buffer1
if (_buffer.CheckWaferNextStepIsThis(schedulerPm.Module, 0))
{
if (_buffer.NoTray(0) && _buffer.NoWafer(0))
{
pickPm = schedulerPm.Module;
break;
}
}
else if ((_buffer.NoTray(0) && _buffer.NoWafer(0))
|| (_load.NoTray(0) && _load.NoWafer(0)))
{
pickPm = schedulerPm.Module;
break;
}
}
if (pickPm != ModuleName.System)
{
var pm = GetModule(pickPm.ToString());
if (pm.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(pm.Module, 0, pickBlade))
{
pm.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
}
#endregion
#endregion
#region Logic Check
/// <summary>
/// 获得Buffer的方式和数值
/// </summary>
/// <param name="module"></param>
/// <param name="slot"></param>
/// <param name="coolingType"></param>
/// <param name="setValue"></param>
/// <returns></returns>
private bool GetWaferSequenceNextValue(ModuleName module, int slot, string nodeName, out string nodeValue)
{
nodeValue = "";
if (!GetModule(module).HasWafer(slot))
return false;
WaferInfoRt wafer = GetModule(module).GetWaferInfo(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;
nodeValue = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter[nodeName].ToString();
if (String.IsNullOrEmpty(nodeValue))
{
return false;
}
return true;
}
private bool GetWaferSequenceCurrentValue(ModuleName module, int slot, string nodeName, out string nodeValue)
{
nodeValue = "";
if (!GetModule(module).HasWafer(slot))
return false;
WaferInfoRt wafer = GetModule(module).GetWaferInfo(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 - 1].StepModules.Contains(module))
return false;
nodeValue = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep - 1].StepParameter[nodeName].ToString();
if (String.IsNullOrEmpty(nodeValue))
{
return false;
}
return true;
}
public bool CheckBufferWaferHasJob()
{
WaferInfoRt wafer = _buffer.GetWaferInfo(0);
if (wafer.IsWaferEmpty)
{
return false;
}
if (wafer.ProcessJob == null)
{
return false;
}
var pj = _processJobList.Find(x => x.InnerId == wafer.ProcessJob.InnerId);
if (pj == null)
{
return false;
}
return true;
}
public bool CheckWaferProcessModuleIsAvailable(ModuleName waferModule, int waferSlot)
{
var wafer = GetModule(waferModule).GetWaferInfo(waferSlot);
if (wafer.IsWaferEmpty)
return false;
if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
return false;
if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
return false;
//foreach (var module in wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules)
//{
//if (GetModule(module).NoWafer(0)
// && _lstPms.Find(x => x.Module == module).IsAvailable
// && !CheckNeedRunClean(module, out bool _, out string _))
// return true;
//}
foreach (var step in wafer.ProcessJob.Sequence.Steps)
{
foreach (var module in step.StepModules)
{
if (module.ToString().StartsWith("PM")
&& GetModule(module).NoWafer(0)
&& _lstPms.Find(x => x.Module == module).IsAvailable
&& !GetModule(module).CheckNeedRunClean(out var _, out var _))
return true;
}
}
return false;
}
public bool CheckWaferSequenceStepDone(ModuleName waferModule, int waferSlot)
{
var wafer = WaferManager.Instance.GetWafer(waferModule, waferSlot);
if (wafer.IsWaferEmpty)
{
return false;
}
if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
{
return false;
}
if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count && wafer.ProcessJob.Sequence.Steps.Count > 0)
{
return true;
}
return false;
}
private SlotItem SortBySerialMode(List<Tuple<ModuleName, int>> processingWafers)
{
foreach (var pjSlotWafer in processingWafers)
{
if (pjSlotWafer.Item1 == ModuleName.CassAL || pjSlotWafer.Item1 == ModuleName.CassAR)
{
if (GetModule(pjSlotWafer.Item1).CheckWaferNeedProcess(pjSlotWafer.Item2, _pm1.Module))
{
if (GetRunWaferCount(_pm1.Module) < 2)
{
return new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2);
}
else
{
return null;
}
}
else if (GetModule(pjSlotWafer.Item1).CheckWaferNeedProcess(pjSlotWafer.Item2, _pm2.Module))
{
if (GetRunWaferCount(_pm2.Module) < 2)
{
return new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2);
}
else
{
return null;
}
}
}
}
return null;
}
private SlotItem SortByParallelMode(List<Tuple<ModuleName, int>> processingWafers)
{
foreach (var pjSlotWafer in processingWafers)
{
if (pjSlotWafer.Item1 == ModuleName.CassAL || pjSlotWafer.Item1 == ModuleName.CassAR)
{
if (GetModule(pjSlotWafer.Item1).CheckWaferNeedProcess(pjSlotWafer.Item2, _pm1.Module))
{
if (GetRunWaferCount(_pm1.Module) < 2 && GetRunWaferCount(_pm1.Module) <= GetRunWaferCount(_pm2.Module))
{
return new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2);
}
}
else if (GetModule(pjSlotWafer.Item1).CheckWaferNeedProcess(pjSlotWafer.Item2, _pm2.Module))
{
if (GetRunWaferCount(_pm2.Module) < 2 && GetRunWaferCount(_pm2.Module) <= GetRunWaferCount(_pm1.Module))
{
return new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2);
}
}
}
}
return SortBySerialMode(processingWafers);
}
/// <summary>
/// 获取各个模块的Wafer总数量
/// </summary>
/// <returns></returns>
private int GetRunWaferCount()
{
var waferCount = 0;
if (_load.HasWafer(0))
{
waferCount++;
}
if (_unload.HasWafer(0))
{
waferCount++;
}
if (_tmRobot.HasWafer(0))
{
waferCount++;
}
foreach (var pm in _lstPms)
{
if (GetModule(pm.Module).HasWafer(0))
{
waferCount++;
}
}
for (var i = 0; i < 3; i++)
{
if (_buffer.HasWafer(i))
{
waferCount++;
}
}
return waferCount;
}
private int GetRunWaferCount(ModuleName processIn)
{
var waferCount = 0;
if (_tmRobot.HasWafer(0) && (_tmRobot.CheckWaferNeedProcess(0, processIn) || _tmRobot.GetWaferInfo(0).SubstHists.Select(x => x.locationID).Contains(processIn.ToString())))
{
waferCount++;
}
if (GetModule(processIn).HasWafer(0) && (GetModule(processIn).CheckWaferNeedProcess(0, processIn) || GetModule(processIn).GetWaferInfo(0).SubstHists.Select(x => x.locationID).Contains(processIn.ToString())))
{
waferCount++;
}
for (var i = 0; i < 3; i++)
{
if (_buffer.HasWafer(i) && (_buffer.CheckWaferNeedProcess(i, processIn) || _buffer.GetWaferInfo(i).SubstHists.Select(x => x.locationID).Contains(processIn.ToString())))
{
waferCount++;
}
}
return waferCount;
}
/// <summary>
/// 获取各个模块的石墨盘总数量
/// </summary>
/// <returns></returns>
private int GetCurrentTrayCount()
{
var trayCount = 0;
if (_tmRobot.HasTray(0))
{
trayCount++;
}
foreach (var pm in _lstPms)
{
if (GetModule(pm.Module).HasTray(0))
{
trayCount++;
}
}
for (var i = 0; i < 3; i++)
{
if (_buffer.HasTray(i))
{
trayCount++;
}
}
return trayCount;
}
/// <summary>
/// 获取ProcessJob可以同时运行工艺的Wafer总数
/// </summary>
/// <returns></returns>
private int GetCurrentWaferCount()
{
var waferCountDiv = 0;
var cassWaferCount = 0;
foreach (var cj in _controlJobList)
{
if (cj.State == EnumControlJobState.Executing)
{
foreach (var pj in _processJobList)
{
if (pj.ControlJobName == cj.Name && pj.State == EnumProcessJobState.Processing)
{
cassWaferCount += pj.SlotWafers.Count;
foreach (var pjSlotWafer in pj.SlotWafers)
{
var module = GetModule(pjSlotWafer.Item1);
if (module.HasWafer(pjSlotWafer.Item2) && !module.CheckWaferNeedProcess(pjSlotWafer.Item2))
{
waferCountDiv++;
}
}
}
}
}
}
return cassWaferCount - waferCountDiv;
//int waferCount = 0;
//if (_load.HasWafer(0))
//{
// waferCount++;
//}
//for (int i = 0; i < 3; i++)
//{
//if (_buffer.HasWafer(i))
// {
// waferCount++;
// }
//}
//if (_waferRobot.CheckWaferNeedProcess(0) )
//{
// waferCount++;
//}
//if (_aligner.CheckWaferNeedProcess(0) )
//{
// waferCount++;
//}
//for (int i=0;i<25;i++)
//{
// if (CheckWaferNeedProcess(ModuleName.CassAL, i))
// {
// waferCount++;
// }
// if (CheckWaferNeedProcess(ModuleName.CassAR, i))
// {
// waferCount++;
// }
//}
//return waferCount;
}
#endregion
#region Module error
public Result MonitorModuleError()
{
var isModuleError = false;
var isPMError = new bool[2];
for (var i = 0; i < isPMError.Length; i++)
{
isPMError[i] = false;
}
if (_tmRobot.IsError)
isModuleError = true;
for (var i = 0; i < _lstPms.Count; i++) // PM出错不影响其他腔体的传片
{
if (_lstPms[i].IsError)
isPMError[i] = true;
}
if (isModuleError && !_isModuleErrorPrevious)
{
}
else if (!isModuleError && _isModuleErrorPrevious)
{
Reset();
}
for (var i = 0; i < _lstPms.Count; i++)
{
if (!isPMError[i] && _isPMErrorPrevious[i])
{
_lstPms[i].ResetTask();
}
_isPMErrorPrevious[i] = isPMError[i];
}
_isModuleErrorPrevious = isModuleError;
return Result.RUN;
}
private bool CheckModuleHaveWaferWithNoJob(out string reason)
{
reason = "";
if (_controlJobList.Count > 0)
{
reason = "lstControlJobs.Count > 0";
return false;
}
else
{
if (_buffer.HasWafer(0) || _buffer.HasWafer(1) || _buffer.HasWafer(2))
{
reason = $"Buffer have wafer!";
EV.PostWarningLog(LogSource, reason);
return true;
}
if (_tmRobot.HasWafer(0))
{
reason = $"TmRobot have wafer!";
EV.PostWarningLog(LogSource, reason);
return true;
}
if (!_load.HasWafer(0))
{
reason = $"Load have no wafer!";
EV.PostWarningLog(LogSource, reason);
return true;
}
if (!_load.HasTray(0))
{
reason = $"Load have no Tray!";
EV.PostWarningLog(LogSource, reason);
return true;
}
return false;
}
}
private bool CheckWaferNeedProcess(ModuleName module, int waferSlot, ModuleName processIn = ModuleName.System)
{
WaferInfoRt wafer = WaferManager.Instance.GetWafer(module, waferSlot);
if (wafer.IsWaferEmpty)
return false;
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;
var 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;
}
#endregion
}
}