SicMultiplate/SicRT/Equipments/AutoTransfer.cs

3821 lines
141 KiB
C#
Raw Normal View History

2023-03-03 15:42:13 +08:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Media.Imaging;
using Aitex.Core.Common;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.RecipeCenter;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using Aitex.Sorter.Common;
using MECF.Framework.Common.DataCenter;
using MECF.Framework.Common.DBCore;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.Jobs;
using MECF.Framework.Common.Schedulers;
using MECF.Framework.Common.SubstrateTrackings;
using SicRT.Equipments.Schedulers;
using SicRT.Modules.Schedulers;
using SicRT.Scheduler;
namespace SicRT.Modules
{
public partial class AutoTransfer : SchedulerModuleFactory
{
public class TrayInfo
{
public int TrayModule { get; set; }
public int TraySlot { get; set; }
public int TrayProcessCount { get; set; }
}
private List<ControlJobInfo> _lstNeedMapJob = new List<ControlJobInfo>();
private List<ControlJobInfo> _lstControlJobs = new List<ControlJobInfo>();
private List<ProcessJobInfo> _lstProcessJobs = new List<ProcessJobInfo>();
private List<TrayInfo> _lstProcessedTrayInfo = new List<TrayInfo>(); //保存石墨盘的进入腔体的信息(最多4次工艺需要换盘)
private int _maxTrayCount = 4; //可以同时运行的石墨盘总数
private bool _cassProcessOnebyOne = false; //Cassette是左右交互取片还是一个Cassette取完再取另一个
private R_TRIG NotifyTrayExhausted = new R_TRIG();
private R_TRIG _trigIsPumping = new R_TRIG();
private const string LogSource = "Scheduler";
private SchedulerDBCallback _dbCallback;
public bool CassetteFromAToB => SC.GetValue<bool>("System.Scheduler.CassetteFromAToB");
private bool _isCycleMode;
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 string _timeBuffer1 { get; set; }
private string _timeBuffer2 { get; set; }
private string _timeBuffer3 { get; set; }
private Dictionary<string, DateTime> _bufferWaferInfo = new Dictionary<string, DateTime>();
Queue<Action> waferRobotActions = new Queue<Action>() { };
Queue<Action> trayRobotActions = new Queue<Action>() { };
Queue<Action> tmRobotActions = new Queue<Action>() { };
public AutoTransfer()
{
_dbCallback = new SchedulerDBCallback();
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("CassAL.LocalJobName", () =>
{
var jb = _lstControlJobs.FirstOrDefault(x => x.Module == "CassAL");
if (jb != null)
return jb.Name;
return "";
});
DATA.Subscribe("CassAL.LocalJobStatus", () =>
{
var jb = _lstControlJobs.FirstOrDefault(x => x.Module == "CassAL");
if (jb != null)
return jb.State.ToString();
return "";
});
DATA.Subscribe("CassAR.LocalJobName", () =>
{
var jb = _lstControlJobs.FirstOrDefault(x => x.Module == "CassAR");
if (jb != null)
return jb.Name;
return "";
});
DATA.Subscribe("CassAR.LocalJobStatus", () =>
{
var jb = _lstControlJobs.FirstOrDefault(x => x.Module == "CassAR");
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;
});
waferRobotActions.Enqueue(MonitorWaferRobotCassettePlaceTask);
waferRobotActions.Enqueue(MonitorWaferRobotCassettePickTask);
waferRobotActions.Enqueue(MonitorWaferRobotUnLoadPickTask);
waferRobotActions.Enqueue(MonitorWaferRobotAlignerPlaceTask);
waferRobotActions.Enqueue(MonitorWaferRobotAlignerPickTask);
waferRobotActions.Enqueue(MonitorWaferRobotLoadPlaceTask);
trayRobotActions.Enqueue(MonitorTrayRobotLoadPlaceTask);
trayRobotActions.Enqueue(MonitorTrayRobotLoadPickTask);
trayRobotActions.Enqueue(MonitorTrayRobotCassettePlaceTask);
trayRobotActions.Enqueue(MonitorTrayRobotCassettePickTask);
tmRobotActions.Enqueue(MonitorTmRobotPMPlaceTask);
tmRobotActions.Enqueue(MonitorTmRobotPMPickTask);
tmRobotActions.Enqueue(MonitorTmRobotBufferPlaceTask);
tmRobotActions.Enqueue(MonitorTmRobotBufferPickTask);
tmRobotActions.Enqueue(MonitorTmRobotLoadPlaceTask);
tmRobotActions.Enqueue(MonitorTmRobotLoadPickTask);
tmRobotActions.Enqueue(MonitorTmRobotUnLoadPlaceTask);
tmRobotActions.Enqueue(MonitorTmRobotUnLoadPickTask);
}
public bool HasJobRunning
{
get { return _lstControlJobs.Count > 0; }
}
public void Clear()
{
_tmRobot.ResetTask();
_waferRobot.ResetTask();
_trayRobot.ResetTask();
foreach (var pm in _lstPms)
{
pm.ResetTask();
}
foreach (var cass in _lstWaferCassettes)
{
cass.ResetTask();
}
_cassetteBL.ResetTask();
_load.ResetTask();
_unload.ResetTask();
_buffer.ResetTask();
_lstControlJobs.Clear();
_lstProcessJobs.Clear();
_bufferWaferInfo.Clear();
}
public void ResetTask()
{
if(!_tmRobot.IsOnline)
{
_tmRobot.ResetTask();
}
if(!_waferRobot.IsOnline)
{
_waferRobot.ResetTask();
}
if(!_trayRobot.IsOnline)
{
_trayRobot.ResetTask();
}
if (!_load.IsOnline)
{
_load.ResetTask();
}
if (!_unload.IsOnline)
{
_unload.ResetTask();
}
if (!_buffer.IsOnline)
{
_buffer.ResetTask();
}
foreach (var pm in _lstPms)
{
if (!pm.IsOnline)
{
pm.ResetTask();
}
}
foreach (var cass in _lstWaferCassettes)
{
if (!cass.IsOnline)
{
cass.ResetTask();
}
}
if (!_cassetteBL.IsOnline)
{
_cassetteBL.ResetTask();
}
}
public void GetConfig()
{
_cycledCount = 0;
_isCycleMode = SC.GetValue<bool>("System.IsCycleMode");
_cycleSetPoint = _isCycleMode ? SC.GetValue<int>("System.CycleCount") : 0;
_maxTrayCount = _lstPms.Count * 2;
}
public bool CreateJob(Dictionary<string, object> param)
{
string reason = "";
string[] slotSequence = (string[])param["SlotSequence"];
string jobId = (string)param["JobId"];
string module = (string)param["Module"];
bool autoStart = (bool)param["AutoStart"];
string lotId = jobId;
if (param.ContainsKey("LotId"))
lotId = (string)param["LotId"];
//if (CheckModuleHaveWaferWithNoJob(out reason))
//{
// EV.PostWarningLog(LogSource, $"{reason}");
// return false;
//}
if (!ValidateSequence(slotSequence, out reason))
{
EV.PostWarningLog(LogSource, $"{reason}");
return false;
}
if (slotSequence.Length != 25)
{
reason = $"slot sequence parameter not valid, length is {slotSequence.Length}, should be 25";
EV.PostWarningLog(LogSource, reason);
return false;
}
if (string.IsNullOrEmpty(jobId))
{
jobId = "CJ_Local_" + module + DateTime.Now;
}
if (_lstControlJobs.Exists(x => x.Name == jobId))
{
reason = $"LotID : {jobId} already created";
EV.PostWarningLog(LogSource, reason);
return false;
}
ControlJobInfo cj = new ControlJobInfo();
cj.Name = jobId;
cj.Module = module;
cj.LotName = jobId;
cj.LotInnerId = Guid.NewGuid();
2023-03-13 17:37:55 +08:00
cj.LotWafers = new List<WaferInfoRt>();
2023-03-03 15:42:13 +08:00
cj.SetState(EnumControlJobState.WaitingForStart);
Dictionary<string, bool[]> seqSlot = new Dictionary<string, bool[]>();
Dictionary<string, List<Tuple<ModuleName, int>>> seqSlotWafers = new Dictionary<string, List<Tuple<ModuleName, int>>>();
Dictionary<string, string> indexSequence = new Dictionary<string, string>();
bool enableGroupBySequence = SC.GetValue<bool>("System.Scheduler.GroupWaferBySequence");
string WaferAssociationInfo = $"WaferAssociationInfo({module}):";
for (int i = 0; i < 25; i++)
{
WaferAssociationInfo = WaferAssociationInfo + string.Format(" slot{0} -- {1};", i + 1, slotSequence[i]);
if (string.IsNullOrEmpty(slotSequence[i]) || string.IsNullOrEmpty(slotSequence[i].Trim()))
continue;
string groupName = enableGroupBySequence ? slotSequence[i].Trim() : i.ToString();
indexSequence[groupName] = slotSequence[i];
if (!seqSlot.ContainsKey(groupName))
{
seqSlot[groupName] = new bool[25];
}
if (!seqSlotWafers.ContainsKey(groupName))
{
seqSlotWafers[groupName] = new List<Tuple<ModuleName, int>>();
}
seqSlot[groupName][i] = true;
if (!WaferManager.Instance.CheckHasWafer(module, i))
{
reason = $"job wafer: {module} slot {i + 1} not in the carrier";
EV.PostWarningLog(LogSource, reason);
return false;
}
if (!WaferManager.Instance.CheckWafer(ModuleHelper.Converter(module), i, WaferStatus.Normal))
{
reason = $"job wafer: {module} slot {i + 1} status is {WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).Status}";
EV.PostWarningLog(LogSource, reason);
return false;
}
var wafer = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i);
if (wafer == null || wafer.IsEmpty)
{
reason = $"specifies wafer: {module} slot {i + 1} not in the carrier";
EV.PostWarningLog(LogSource, reason);
return false;
}
if (wafer.ProcessState != EnumWaferProcessStatus.Idle)
{
reason = $"specifies wafer: {module} slot {i + 1} process state is not idle";
EV.PostWarningLog(LogSource, reason);
return false;
}
if (wafer.ProcessJob != null)
{
reason = $"specifies wafer: {module} slot {i + 1} ProcessJob is not null";
EV.PostWarningLog(LogSource, reason);
return false;
}
if (wafer.SubstE90Status != EnumE90Status.NeedProcessing)
{
reason = $"specifies wafer: {module} slot {i + 1} SubstE90Status is not NeedProcessing";
EV.PostWarningLog(LogSource, reason);
return false;
}
seqSlotWafers[groupName].Add(Tuple.Create(ModuleHelper.Converter(module), i));
cj.LotWafers.Add(WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i));
WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).PPID = slotSequence[i];
}
//currentSlotSequenceList[module] = slotSequence.Reverse().ToList();
EV.PostInfoLog(LogSource, WaferAssociationInfo);
if (seqSlotWafers.Count == 0)
{
reason = $"Can not create job, no wafer assigned";
EV.PostWarningLog(LogSource, reason);
return false;
}
List<ProcessJobInfo> pjs = new List<ProcessJobInfo>();
string[] seqs = seqSlot.Keys.ToArray();
for (int i = 0; i < seqs.Length; i++)
{
ProcessJobInfo pj = new ProcessJobInfo();
pj.Name = jobId + "_" + (i + 1);
pj.Sequence = SequenceInfoHelper.GetInfo(indexSequence[seqs[i]]);
pj.ControlJobName = cj.Name;
//pj.LotName = lotId;
pj.SlotWafers = seqSlotWafers[seqs[i]];
pj.SetState(EnumProcessJobState.Queued);
//检查PM的状态
if (!CheckSequencePmReady(pj.Sequence))
{
return false;
}
//if (!CheckSequenceRecipeFileValid(pj.Sequence, out reason))
//{
// reason = $"recipe file not valid in the sequence, {reason}";
// EV.PostWarningLog(LogSource, reason);
// return false;
//}
//if (!CheckSequenceOrderOk(pj.Sequence, out reason))
//{
// reason = $"sequence path not valid, {reason}";
// EV.PostWarningLog(LogSource, reason);
// return false;
//}
pjs.Add(pj);
}
foreach (var pj in pjs)
{
cj.ProcessJobNameList.Add(pj.Name);
_lstProcessJobs.Add(pj);
}
_lstControlJobs.Add(cj);
int totalWafer = 0;
foreach (var pj in pjs)
{
foreach (var pjSlotWafer in pj.SlotWafers)
{
2023-03-13 17:37:55 +08:00
var wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
2023-03-03 15:42:13 +08:00
wafer.ProcessJob = pj;
WaferDataRecorder.SetCjInfo(wafer.InnerId.ToString(), cj.InnerId.ToString());
WaferDataRecorder.SetWaferSequence(wafer.InnerId.ToString(), pj.Sequence.Name);
WaferDataRecorder.SetWaferLotId(wafer.InnerId.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}");
CarrierInfo carrier = CarrierManager.Instance.GetCarrier(cj.Module);
JobDataRecorder.StartCJ(cj.InnerId.ToString(), carrier.InnerId.ToString(), cj.Name, cj.Module, cj.Module, totalWafer);
return true;
}
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("PurgeCount") || !sequence.Steps[currentIndex].StepParameter.ContainsKey("PumpDelayTime"))
{
reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Buffer PurgeCount or PumpDelayTime 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;
}
public bool CreateControlJob(string jobId, string module, List<string> pjIDs, bool isAutoStart)
{
if (_lstControlJobs.Exists(x => x.Name == jobId))
{
EV.PostWarningLog(LogSource, $"{jobId} is already created");
return false;
}
if (!ModuleHelper.IsCassette(ModuleHelper.Converter(module)))
{
EV.PostWarningLog(LogSource, $"{module} should be Cassete");
return false;
}
if (_lstProcessJobs.Count <= 0) //判断上一步ProcessJob是否创建成功
{
EV.PostWarningLog(LogSource, $"process job is not exist");
return false;
}
ControlJobInfo cj = new ControlJobInfo();
cj.Name = jobId;
cj.Module = module;
cj.LotName = jobId;
cj.LotInnerId = Guid.NewGuid();
2023-03-13 17:37:55 +08:00
cj.LotWafers = new List<WaferInfoRt>();
2023-03-03 15:42:13 +08:00
cj.SetState(EnumControlJobState.WaitingForStart);
int totalWafer = 0;
foreach (var pjName in pjIDs)
{
var pj = _lstProcessJobs.FirstOrDefault(x => x.Name == pjName);
if (pj == null)
{
LOG.Info($"not find {pjName} while create control job");
continue;
}
var slotWafers = new List<Tuple<ModuleName, int>>();
foreach (var slotWafer in pj.SlotWafers)
{
var _module = GetModule(module);
if (!_module.HasWafer(slotWafer.Item2))
{
EV.PostWarningLog(LogSource, $"job wafer: {module} slot {slotWafer.Item2 + 1} not in the carrier");
return false;
}
if (!_module.CheckWaferStatus(slotWafer.Item2, WaferStatus.Normal))
{
EV.PostWarningLog(LogSource, $"job wafer: {module} slot {slotWafer.Item2 + 1} status is {_module.GetWaferInfo(slotWafer.Item2).Status}");
return false;
}
if (_module.GetWaferInfo(slotWafer.Item2).ProcessState != EnumWaferProcessStatus.Idle)
{
EV.PostWarningLog(LogSource, $"job wafer: {module} slot {slotWafer.Item2 + 1} process status is {_module.GetWaferInfo(slotWafer.Item2).ProcessState}");
return false;
}
slotWafers.Add(Tuple.Create(ModuleHelper.Converter(module), slotWafer.Item2));
totalWafer++;
}
pj.ControlJobName = cj.Name;
cj.ProcessJobNameList.Add(pj.Name);
pj.SlotWafers = slotWafers;
foreach (var pjSlotWafer in pj.SlotWafers)
{
2023-03-13 17:37:55 +08:00
var wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(pjSlotWafer.Item2);
2023-03-03 15:42:13 +08:00
cj.LotWafers.Add(wafer);
wafer.ProcessJob = pj;
wafer.ProcessJobID = pj.Sequence.Name;
WaferDataRecorder.SetCjInfo(wafer.InnerId.ToString(), cj.InnerId.ToString());
WaferDataRecorder.SetWaferSequence(wafer.InnerId.ToString(), pj.Sequence.Name);
WaferDataRecorder.SetWaferLotId(wafer.InnerId.ToString(), jobId);
WaferManager.Instance.UpdateWaferLotId(pjSlotWafer.Item1, pjSlotWafer.Item2, jobId);
}
}
_lstControlJobs.Add(cj);
CarrierManager.Instance.DeleteCarrier(cj.Module);
CarrierManager.Instance.CreateCarrier(cj.Module);
CarrierManager.Instance.UpdateCarrierId(cj.Module, $"{cj.Module} {DateTime.Now}");
CarrierInfo carrier = CarrierManager.Instance.GetCarrier(cj.Module);
JobDataRecorder.StartCJ(cj.InnerId.ToString(), carrier.InnerId.ToString(), cj.Name, cj.Module, cj.Module, totalWafer);
return true;
}
public bool CreateProcessJob(string jobId, string sequenceName, List<int> slotNumbers/*0 based*/, bool isAutoStart)
{
var sequenceInfo = SequenceInfoHelper.GetInfo(sequenceName);
//模块顺序检查
List<int> lstLoad = new List<int>();
List<int> lstBuffer = new List<int>();
List<int> lstUnLoad = new List<int>();
List<int> lstPM = new List<int>();
for (int i = 0; i < sequenceInfo.Steps.Count; i++)
{
if (sequenceInfo.Steps[i].StepModules.Count == 0)
{
return false;
}
if (sequenceInfo.Steps[i].StepModules.Any(pm => ModuleHelper.IsPm(pm)))
{
lstPM.Add(i);
}
if (sequenceInfo.Steps[i].StepModules.Any(load => load == ModuleName.Load || load == ModuleName.LoadLock))
{
lstLoad.Add(i);
}
if (sequenceInfo.Steps[i].StepModules.Any(unload => unload == ModuleName.UnLoad))
{
lstUnLoad.Add(i);
}
if (sequenceInfo.Steps[i].StepModules.Any(buff => buff == ModuleName.Buffer))
{
lstBuffer.Add(i);
}
}
if (lstPM.Count <= 0)
{
EV.PostWarningLog(LogSource, $"Sequence must have pm step info!");
return false;
}
if (lstLoad.Count > 1)
{
EV.PostWarningLog(LogSource, $"Sequence can not contain {lstLoad.Count} Load Step!");
return false;
}
if (lstUnLoad.Count > 1)
{
EV.PostWarningLog(LogSource, $"Sequence can not contain {lstUnLoad.Count} UnLoad Step!");
return false;
}
if (lstBuffer.Count > 0)
{
foreach (int bufferId in lstBuffer)
{
if (lstLoad.Count == 1)
{
if (bufferId < lstLoad[0])
{
EV.PostWarningLog(LogSource, $"Sequence Load Step Must Before Buffer Step!");
return false;
}
}
if (lstUnLoad.Count == 1)
{
if (bufferId > lstUnLoad[0])
{
EV.PostWarningLog(LogSource, $"Sequence Buffer Step Must Before UnLoad Step!");
return false;
}
}
}
}
var slotWafers = new List<Tuple<ModuleName, int>>();
foreach (var slot in slotNumbers)
{
slotWafers.Add(Tuple.Create(ModuleName.System, slot));
}
ProcessJobInfo pj = new ProcessJobInfo();
pj.Name = jobId;
pj.Sequence = sequenceInfo;
pj.SlotWafers = slotWafers;
pj.SetState(EnumProcessJobState.Queued);
_lstProcessJobs.Add(pj);
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 _lstControlJobs)
{
foreach (var pj in _lstProcessJobs)
{
if (pj.ControlJobName == cj.Name)
{
pj.SetState(EnumProcessJobState.Stopping);
}
}
if (_cycleSetPoint > 0)
{
_cycleSetPoint = _cycledCount;
}
}
}
internal void AbortJob(string jobName)
{
ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
if (cj == null)
{
EV.PostWarningLog(LogSource, $"abort job rejected, not found job with id {jobName}");
return;
}
int unprocessed_cj = 0;
int aborted_cj = 0;
List<ProcessJobInfo> pjAbortList = new List<ProcessJobInfo>();
foreach (var pj in _lstProcessJobs)
{
if (pj.ControlJobName == cj.Name)
{
pj.SetState(EnumProcessJobState.Aborting);
pjAbortList.Add(pj);
int unprocessed = 0;
int aborted = 0;
2023-03-13 17:37:55 +08:00
var wafers = WaferManager.Instance.GetWaferByProcessJob(pj.Name);
2023-03-03 15:42:13 +08:00
foreach (var waferInfo in wafers)
{
waferInfo.ProcessJob = null;
waferInfo.NextSequenceStep = 0;
if (waferInfo.ProcessState != EnumWaferProcessStatus.Completed)
{
unprocessed++;
unprocessed_cj++;
}
}
JobDataRecorder.EndPJ(pj.InnerId.ToString(), aborted, unprocessed);
}
}
foreach (var pj in pjAbortList)
{
_lstProcessJobs.Remove(pj);
}
_lstControlJobs.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 _lstControlJobs)
{
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 _lstControlJobs)
{
if (cj.State == EnumControlJobState.Executing)
{
cj.SetState(EnumControlJobState.Paused);
}
}
}
internal bool CheckSequencePmReady(SequenceInfo seqInfo)
{
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", $"can not start job, {moduleName} is not be error");
return false;
}
if (!module.IsOnline)
{
EV.PostWarningLog("Scheduler", $"can not start job, {moduleName} is not be online");
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;
}
internal void StartJob(string jobName)
{
GetConfig();
ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
if (cj == null)
{
EV.PostWarningLog(LogSource, $"start job rejected, not found job with id {jobName}");
return;
}
foreach (var needProcessWafer in cj.LotWafers)
{
if (CheckWaferNeedProcess((ModuleName)needProcessWafer.OriginStation, needProcessWafer.OriginSlot, ModuleName.PM1))
{
if (_pm1.IsError)
{
EV.PostWarningLog("Scheduler", "can not start job, pm1 is in error");
return;
}
if (_pm1.IsService)
{
EV.PostWarningLog("Scheduler", "can no tstart job, PM1 is Service Mode");
return;
}
}
else if (CheckWaferNeedProcess((ModuleName)needProcessWafer.OriginStation, needProcessWafer.OriginSlot, ModuleName.PM2))
{
if (_pm2.IsError)
{
EV.PostWarningLog("Scheduler", "can not start job, pm2 is in error");
return;
}
if (_pm2.IsService)
{
EV.PostWarningLog("Scheduler", "can no tstart job, PM2 is Service Mode");
return;
}
}
}
//foreach (var cj in _lstControlJobs)
{
if (cj.State == EnumControlJobState.WaitingForStart)
{
cj.BeginTime = DateTime.Now;
cj.LotInnerId = Guid.NewGuid();
_dbCallback.LotCreated(cj);
cj.SetState(EnumControlJobState.Executing);
}
}
}
/// <summary>
/// Start Auto Transfer
/// </summary>
/// <param name="objs"></param>
/// <returns></returns>
public Result Start(params object[] objs)
{
GetConfig();
_cycledWafer = 0;
_cycledCount = 0;
bool hasPmOnline = false;
foreach (var schedulerPm in _lstPms)
{
if (schedulerPm.IsOnline && !schedulerPm.IsError)
{
hasPmOnline = true;
break;
}
}
if (!hasPmOnline)
{
EV.PostWarningLog("Scheduler", "can not change to auto mode, at least one process chamber be online and no error");
return Result.FAIL;
}
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;
}
//Exhaust 耗尽
public Result Monitor()
{
NotifyTrayExhausted.CLK = CheckTrayExhausted();
if (NotifyTrayExhausted.Q)
{
EV.PostAlarmLog("System", "Tray ProcessCount Exhausted , No Tray for next Process !");
}
ControlJobInfo cjActive = _lstControlJobs.Find(x => x.State == EnumControlJobState.Executing);
if (cjActive != null)
{
MonitorModuleTasks();
}
MonitorModuleError();
MonitorJobTasks();
return Result.RUN;
}
public Result MonitorJobTasks()
{
UpdateProcessJobStatus();
UpdateControlJobStatus();
StartNewJob();
return Result.RUN;
}
protected bool CheckAllWaferReturned(ProcessJobInfo pj, bool checkAllProcessed)
{
for (int i = 0; i < pj.SlotWafers.Count; ++i)
{
2023-03-13 17:37:55 +08:00
var wafer = GetModule(GetWaferReturnedCassette(pj.SlotWafers[i].Item1)).GetWaferInfo(pj.SlotWafers[i].Item2);
2023-03-03 15:42:13 +08:00
if (wafer.IsEmpty)
return false;
if (checkAllProcessed && GetModule(GetWaferReturnedCassette(pj.SlotWafers[i].Item1)).CheckWaferNeedProcess(pj.SlotWafers[i].Item2))
return false;
if (wafer.ProcessJob == null || wafer.ProcessJob.InnerId != pj.InnerId)
{
return false;
}
}
return true;
}
private ModuleName GetWaferReturnedCassette(ModuleName moduleFrom)
{
if (CassetteFromAToB)
{
if (moduleFrom == ModuleName.CassAL)
{
return ModuleName.CassAR;
}
else if (moduleFrom == ModuleName.CassAR)
{
return ModuleName.CassAL;
}
}
return moduleFrom;
}
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 _lstProcessJobs)
{
if (pj.State == EnumProcessJobState.Processing)
{
if (CheckAllWaferReturned(pj, true) && CheckAllPmCleaned(pj) && CheckAllDummyWaferReturned())
{
if (_unload.IsAvailable && _buffer.IsAvailable && _tmRobot.IsAvailable && _load.IsAvailable
&& _waferRobot.IsAvailable && _unload.NoTray(0)
&& _trayRobot.IsAvailable && _tmRobot.NoTray(0)
&& _load.NoTray(0) && _waferRobot.NoWafer(0) && _trayRobot.NoTray(0))
{
pj.SetState(EnumProcessJobState.ProcessingComplete);
JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0);
}
}
}
else if (pj.State == EnumProcessJobState.Stopping)
{
if (CheckAllWaferReturned(pj, false) && CheckAllPmCleaned(pj) && CheckAllDummyWaferReturned())
{
if (_unload.IsAvailable && _buffer.IsAvailable && _tmRobot.IsAvailable && _load.IsAvailable
&& _waferRobot.IsAvailable && _unload.NoTray(0)
&& _trayRobot.IsAvailable && _tmRobot.NoTray(0)
&& _load.NoTray(0) && _waferRobot.NoWafer(0) && _trayRobot.NoTray(0))
{
pj.SetState(EnumProcessJobState.ProcessingComplete);
JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0);
}
}
}
}
}
private void UpdateControlJobStatus()
{
if (_lstControlJobs.Count == 0)
return;
bool allControlJobComplete = true;
List<ControlJobInfo> cjRemoveList = new List<ControlJobInfo>();
foreach (var cj in _lstControlJobs)
{
if (cj.State == EnumControlJobState.Executing)
{
bool allPjCompleted = true;
foreach (var pjName in cj.ProcessJobNameList)
{
var pj = _lstProcessJobs.Find(x => x.Name == pjName);
if (pj == null)
{
LOG.Error($"Not find pj named {pjName} in {cj.Name}");
continue;
}
if (pj.State != EnumProcessJobState.Complete && pj.State != EnumProcessJobState.ProcessingComplete)
{
allPjCompleted = false;
break;
}
}
if (allPjCompleted)
{
cj.SetState(EnumControlJobState.Completed);
int unprocessed_cj = 0;
int aborted_cj = 0;
foreach (var pj in _lstProcessJobs)
{
if (pj.ControlJobName == cj.Name)
{
int unprocessed = 0;
int aborted = 0;
2023-03-13 17:37:55 +08:00
var wafers = WaferManager.Instance.GetWaferByProcessJob(pj.Name);
2023-03-03 15:42:13 +08:00
foreach (var waferInfo in wafers)
{
waferInfo.ProcessJob = null;
waferInfo.NextSequenceStep = 0;
if (waferInfo.ProcessState != EnumWaferProcessStatus.Completed)
{
unprocessed++;
unprocessed_cj++;
}
}
JobDataRecorder.EndPJ(pj.InnerId.ToString(), aborted, unprocessed);
}
}
JobDataRecorder.EndCJ(cj.InnerId.ToString(), aborted_cj, unprocessed_cj);
_dbCallback.LotFinished(cj);
}
}
if (cj.State == EnumControlJobState.Completed)
{
cjRemoveList.Add(cj);
}
allControlJobComplete = allControlJobComplete && cj.State == EnumControlJobState.Completed;
}
//if (_isCycleMode && _cycledCount < _cycleSetPoint)
//{
// int countPerCycle = 0;
// int countProcessed = 0;
// foreach (var pj in _lstProcessJobs)
// {
// foreach (var pjSlotWafer in pj.SlotWafers)
// {
// countPerCycle++;
// WaferInfo wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(pjSlotWafer.Item2);
// if (!wafer.IsEmpty && !GetModule(pjSlotWafer.Item1).CheckWaferNeedProcess(pjSlotWafer.Item2))
// countProcessed++;
// }
// }
// _cycledWafer = _cycledCount * countPerCycle + countProcessed;
// //StatsDataManager.Instance.SetValue(StatsNameTotalRunningWafer, _totalWaferWhenStart + _cycledWafer);
// if (allControlJobComplete)
// {
// _cycledCount++;
// if (_cycledCount < _cycleSetPoint)
// {
// foreach (var cj in _lstControlJobs)
// {
// cj.SetState(EnumControlJobState.Executing);
// }
// foreach (var pj in _lstProcessJobs)
// {
// pj.SetState(EnumProcessJobState.Queued);
// pj.InnerId = Guid.NewGuid();
// foreach (var pjSlotWafer in pj.SlotWafers)
// {
// WaferInfo wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(pjSlotWafer.Item2);
// wafer.ProcessJob = null;
// wafer.NextSequenceStep = 0;
// wafer.ProcessState = EnumWaferProcessStatus.Idle;
// }
// }
// }
// }
//}
foreach (var cj in cjRemoveList)
{
List<ProcessJobInfo> pjRemoveList = new List<ProcessJobInfo>();
foreach (var pj in _lstProcessJobs)
{
if (pj.ControlJobName == cj.Name)
pjRemoveList.Add(pj);
}
foreach (var pj in pjRemoveList)
{
_lstProcessJobs.Remove(pj);
}
_lstControlJobs.Remove(cj);
}
//ControlJobInfo cjActived = null;
//foreach (var cj in _lstControlJobs)
//{
// if (cj.State == EnumControlJobState.Executing)
// {
// cjActived = cj;
// break;
// }
//}
}
private void StartNewJob()
{
foreach (var cj in _lstControlJobs)
{
if (cj.State == EnumControlJobState.Executing)
{
foreach (var pjName in cj.ProcessJobNameList)
{
var pj = _lstProcessJobs.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);
}
}
}
}
}
public bool CheckAllJobDone()
{
foreach (var cj in _lstControlJobs)
{
if (cj.State == EnumControlJobState.Executing || cj.State == EnumControlJobState.Paused)
return false;
}
if (_lstControlJobs.Count == 0)
{
return true;
}
return false;
}
private bool ActiveProcessJob(ProcessJobInfo pj)
{
foreach (var pjSlotWafer in pj.SlotWafers)
{
2023-03-13 17:37:55 +08:00
var wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(pjSlotWafer.Item2);
2023-03-03 15:42:13 +08:00
wafer.ProcessJob = pj;
wafer.NextSequenceStep = 0;
WaferDataRecorder.SetPjInfo(wafer.InnerId.ToString(), pj.InnerId.ToString());
}
ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == pj.ControlJobName);
CarrierInfo 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;
}
public Result MonitorModuleTasks()
{
//TMRobot和UnLoad不能同时抽气
_trigIsPumping.CLK = _unload.IsInPumping && _tmRobot.IsInPumping;
if (_trigIsPumping.Q)
{
EV.PostAlarmLog("System", $"检测到 TM.IsInPumping,current Task is {_tmRobot.GetTask()}, _unload.IsInPumping,current Task is {_unload.GetTask()}");
}
MonitorPMTask();
MonitorBufferTask();
MonitorAlignerTask();
MonitorTmRobotTask();
MonitorWaferRobotTask();
MonitorTrayRobotTask();
MonitorLoadTask();
MonitorUnLoadTask();
return Result.RUN;
}
private void MonitorBufferTask()
{
if (!_buffer.IsAvailable)
{
return;
}
if (_buffer.FirstDetectTrayArrive(0)
|| _buffer.FirstDetectTrayArrive(1)
|| _buffer.FirstDetectTrayArrive(2))
{
_buffer.ResetPurgeStatus();
}
for (int i = 0; i < 3; i++)
{
bool canExcute = _buffer.HasWafer(i) && _buffer.CheckWaferNextStepIsThis(_buffer.Module, i);
if (canExcute)
{
2023-03-13 17:37:55 +08:00
var bufferWafer = _buffer.GetWaferInfo(i);
2023-03-03 15:42:13 +08:00
// int bufferSetValue = 0;
//if (!GetWaferSequenceNextValue(ModuleName.Buffer, i, "BufferType", out string strBufferType))
//{
// continue;
//}
//if (!GetWaferSequenceNextValue(ModuleName.Buffer, i, "SetValue", out string strBufferSetValue))
//{
// continue;
//}
if (!GetWaferSequenceNextValue(ModuleName.Buffer, i, "PurgeCount", out var strPurgeLoopCount))
{
continue;
}
if (!GetWaferSequenceNextValue(ModuleName.Buffer, i, "PumpDelayTime", out var strPurgePumpDelay))
{
continue;
}
//if (!Int32.TryParse(strBufferSetValue, out bufferSetValue)
// || !int.TryParse(strPurgeLoopCount, out var purgeLoopCount)
// || !int.TryParse(strPurgePumpDelay, out var purgePumpDelay))
//{
// continue;
//}
if (!int.TryParse(strPurgeLoopCount, out var purgeLoopCount)
|| !int.TryParse(strPurgePumpDelay, out var purgePumpDelay))
{
continue;
}
2023-03-13 17:37:55 +08:00
var wafer = _buffer.GetWaferInfo(i);
2023-03-03 15:42:13 +08:00
//分别判断冷却和加热方式温度是否达到
//if (strBufferType == "HeatByTemp")
//{
// if (_bufferWaferInfo.ContainsKey(bufferWafer.InnerId.ToString()))
// {
// DateTime dtStartTime = _bufferWaferInfo[bufferWafer.InnerId.ToString()];
// double pastTime = (DateTime.Now - dtStartTime).TotalSeconds;
// //选择By温度1秒后再判断温度
// if (pastTime > 1)
// {
// if (_buffer.GetTemperature() >= bufferSetValue)
// wafer.NextSequenceStep++;
// _bufferWaferInfo.Remove(bufferWafer.InnerId.ToString());
// }
// }
// else
// {
// _bufferWaferInfo.Add(bufferWafer.InnerId.ToString(), DateTime.Now);
// }
//}
//else if (strBufferType == "HeatByTime")
//{
// if (_bufferWaferInfo.ContainsKey(bufferWafer.InnerId.ToString()))
// {
// DateTime dtStartTime = _bufferWaferInfo[bufferWafer.InnerId.ToString()];
// double pastTime = (DateTime.Now - dtStartTime).TotalSeconds;
// if (i == 0)
// {
// _timeBuffer1 = pastTime > bufferSetValue ? "0" : (bufferSetValue - pastTime).ToString();
// }
// else if (i == 1)
// {
// _timeBuffer2 = pastTime > bufferSetValue ? "0" : (bufferSetValue - pastTime).ToString();
// }
// if (i == 2)
// {
// _timeBuffer3 = pastTime > bufferSetValue ? "0" : (bufferSetValue - pastTime).ToString();
// }
// if (pastTime > bufferSetValue)
// {
// wafer.NextSequenceStep++;
// _bufferWaferInfo.Remove(bufferWafer.InnerId.ToString());
// }
// }
// else
// {
// _bufferWaferInfo.Add(bufferWafer.InnerId.ToString(), DateTime.Now);
// }
//}
//else if (strBufferType == "CoolingByTime")
//{
// if (_bufferWaferInfo.ContainsKey(bufferWafer.InnerId.ToString()))
// {
// DateTime dtStartTime = _bufferWaferInfo[bufferWafer.InnerId.ToString()];
// double pastTime = (DateTime.Now - dtStartTime).TotalSeconds;
// if (i == 0)
// {
// _timeBuffer1 = pastTime > bufferSetValue ? "0" : (bufferSetValue - pastTime).ToString();
// }
// else if (i == 1)
// {
// _timeBuffer2 = pastTime > bufferSetValue ? "0" : (bufferSetValue - pastTime).ToString();
// }
// if (i == 2)
// {
// _timeBuffer3 = pastTime > bufferSetValue ? "0" : (bufferSetValue - pastTime).ToString();
// }
// if (pastTime > bufferSetValue)
// {
// wafer.NextSequenceStep++;
// _bufferWaferInfo.Remove(bufferWafer.InnerId.ToString());
// }
// }
// else
// {
// _bufferWaferInfo.Add(bufferWafer.InnerId.ToString(), DateTime.Now);
// }
//}
// 如果TMRobot空闲并且Buffer收到新盘则根据Sequence配置进行Purge。
if (_tmRobot.IsAvailable && !_buffer.HasPurged)
{
_tmRobot.Purge(purgeLoopCount, purgePumpDelay);
_buffer.HasPurged = true;
wafer.NextSequenceStep++;
}
return;
}
}
}
private void MonitorLoadTask()
{
if (!_load.IsAvailable)
return;
if (!_tmRobot.IsAvailable && _tmRobot.Target == ModuleName.LoadLock) // 如果TMRobot正在操作LoadLock
return;
if (!_waferRobot.IsAvailable && _waferRobot.Target == ModuleName.LoadLock) // 如果WaferRobot正在操作LoadLock
return;
if (!_trayRobot.IsAvailable && _trayRobot.Target == ModuleName.LoadLock) // 如果TrayRobot正在操作LoadLock
return;
2023-03-03 15:42:13 +08:00
//第一种情况 : 有Wafer有Tray且Load Sequence还未执行
if (_load.HasWafer(0) && _load.HasTrayAndNotExceedProcessCount(0) && _load.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0))
{
if (!_load.CheckWaferTrayGrouped())
{
_load.GroupWaferTray();
return;
}
_load.Purge(_load.GetWaferPurgeCount(0), _load.GetWaferPumpDelayTime(0));
_load.GetWaferInfo(0).NextSequenceStep++;
return;
}
//第二种情况有Wafer有Tray且Load Sequence已执行
else if (_load.HasWafer(0) && _load.HasTrayAndNotExceedProcessCount(0) && !_load.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0))
{
if (!_load.IsReadyForPick(ModuleName.TMRobot, 0))
{
_load.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Pick, 0);
return;
}
}
//第三种情况 : Load腔没盘,TMRobot/Buffer1/2/3中有次数用完的盘
else if (_load.NoTray(0)
&& ((_tmRobot.NoWafer(0) && _tmRobot.HasTrayAndExceedProcessCount(0))
|| (_buffer.NoWafer(0) && _buffer.HasTrayAndExceedProcessCount(0))
|| (_buffer.NoWafer(1) && _buffer.HasTrayAndExceedProcessCount(1))
|| (_buffer.NoWafer(2) && _buffer.HasTrayAndExceedProcessCount(2))))
{
if (!_load.IsReadyForPlace(ModuleName.TMRobot, 0))
{
_load.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0);
return;
}
}
//第四种情况 Load腔没有Wafer且没有Tray
else if (_load.NoWafer(0) && _load.NoTray(0))
{
if (!_load.IsReadyForPlace(ModuleName.WaferRobot, 0))
{
_load.PrepareTransfer(ModuleName.WaferRobot, EnumTransferType.Place, 0);
return;
}
}
//第五种情况 Load腔有次数用完的盘
else if (_load.HasTrayAndExceedProcessCount(0))
{
if (!_load.IsReadyForPick(ModuleName.TrayRobot, 0))
{
_load.PrepareTransfer(ModuleName.TrayRobot, EnumTransferType.Pick, 0);
return;
}
}
else
{
bool IsTrayRobotPlace = false;
foreach (var pm in _lstPms)
{
if (_load.HasWafer(0) && _load.CheckWaferNeedProcess(0, pm.Module) && _load.NoTray(0))
{
if (CheckLoadWaferNeedCassetteTray(pm.Module))
{
IsTrayRobotPlace = true;
break;
}
}
}
if(IsTrayRobotPlace)
{
//第六种情况 : 还没做工艺等TrayRobot来放
if (!_load.IsReadyForPlace(ModuleName.TrayRobot, 0))
{
_load.PrepareTransfer(ModuleName.TrayRobot, EnumTransferType.Place, 0);
return;
}
}
else
{
//第七种情况 : 准备TMRobot来放Tray
if (!_load.IsReadyForPlace(ModuleName.TMRobot, 0))
{
_load.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0);
return;
}
}
}
}
private void MonitorUnLoadTask()
{
if (!_unload.IsAvailable)
{
return;
}
2023-03-11 09:15:28 +08:00
if (!_waferRobot.IsAvailable && _waferRobot.Target == ModuleName.UnLoad) // 如果WaferRobot正在操作UnLoad
return;
if (!_tmRobot.IsAvailable && _tmRobot.Target == ModuleName.UnLoad) // 如果TMRobot正在操作UnLoad
return;
2023-03-03 15:42:13 +08:00
// 重置UnLoad Purge和分离状态
if (_unload.FirstDetectWaferArrive(0) || _unload.FirstDetectWaferLeave(0))
{
_unload.ResetPurgedAndSeparatedStatus();
}
// TM把Wafer和Tray放如UnLoad后先冷却再分离然后取Tray前Purge
if (_unload.HasWafer(0) && _unload.HasTray(0))
{
// 取Tray前Purge
if (!_unload.CheckPurgedBeforeTrayPicking())
{
if (_tmRobot.IsInPumping)
return;
_unload.PurgeBeforeTrayPicking(
_unload.GetWaferPurgeCount(0),
_unload.GetWaferPumpDelayTime(0));
return;
}
// Cooling
if (!_unload.CheckCoolingCompleted())
{
GetWaferSequenceCoolingTime(_unload.Module, 0, out var coolingTime);
_unload.Cooling(true, coolingTime);
return;
}
// 如果没分离,先分离
if (!_unload.CheckWaferTraySeparated())
{
_unload.SeparateWaferTray();
return;
}
}
if (_unload.HasTray(0)) // UnLoad有Tray先让TMRobot取Tray
{
if (_unload.CheckWaferTraySeparated())
{
// 如果Sequence下一步是UnLoad,并且W&T已冷却和分离
if (!_unload.CheckPurgedBeforeTrayPicking())
{
if(_tmRobot.IsInPumping)
{
return;
}
_unload.PurgeBeforeTrayPicking(
_unload.GetWaferPurgeCount(0),
_unload.GetWaferPumpDelayTime(0));
return;
}
// 如果Tray拿走以前还没Purge先Purge在让TMRobot取Tray
if (!_unload.CheckPurgedBeforeTrayPicking())
return;
if (!_unload.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.IsInPumping)
{
return;
}
// UnLoad中有Tray则准备好让TMRobot来取
_unload.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Pick, 0);
return;
}
}
}
else if (_unload.HasWafer(0)) // 如果没Tray下一步让WaferRobot取Wafer
{
if (_unload.CheckWaferTraySeparated())
{
// 如果取Wafer前还未Purge先Purge
if (!_unload.CheckPurgedBeforeWaferPicking() &&
_unload.CheckWaferNextStepIsThis(ModuleName.UnLoad, 0))
{
if (_tmRobot.IsInPumping)
{
return;
}
var cycle = _unload.GetWaferPurgeCount(0, "PurgeCountBeforeWaferPicking");
var pumpDelay = _unload.GetWaferPumpDelayTime(0, "PumpDelayTimeBeforeWaferPicking");
_unload.PurgeBeforeWaferPicking(cycle, pumpDelay);
_unload.GetWaferInfo(0).NextSequenceStep++;
return;
}
if (_unload.CheckPurgedBeforeWaferPicking()
&& !_unload.IsReadyForPick(ModuleName.WaferRobot, 0))
{
if (_tmRobot.IsInPumping)
{
return;
}
// 准备好让WaferRobot来取
_unload.PrepareTransfer(ModuleName.WaferRobot, EnumTransferType.Pick, 0);
}
}
return;
}
else // 如果UnLoad里啥也没有则准备好下次TMRobot喂 W&T
{
// 如果Wafer取完后还没有Purge先Purge
if (!_unload.CheckPurgedAfterWaferPicked())
{
if (_tmRobot.IsInPumping)
{
return;
}
var cycle = _unload.GetWaferPurgeCount(0, "PurgeCountAfterWaferPicking");
var pumpDelay = _unload.GetWaferPumpDelayTime(0, "PumpDelayTimeAfterWaferPicking");
_unload.PurgeAfterWaferPicked(cycle, pumpDelay);
}
// 如果Wafer取完后还没有Purge则终止后去操作。
if (!_unload.CheckPurgedAfterWaferPicked())
return;
if (!_unload.IsReadyForPlace(ModuleName.TMRobot, 0))
{
if (_tmRobot.IsInPumping)
{
return;
}
_unload.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0);
return;
}
}
}
private void MonitorAlignerTask()
{
if (!_aligner.IsAvailable)
{
return;
}
if (_aligner.HasWafer(0) && _aligner.CheckWaferNextStepIsThis(ModuleName.Aligner, 0))
{
_aligner.Aligning();
_aligner.GetWaferInfo(0).NextSequenceStep++;
}
}
private void MonitorPMTask()
{
foreach (var pm in _lstPms)
{
if (!pm.IsAvailable)
{
continue;
}
if (pm.HasWafer(0))
{
//if (pm.CheckNeedRunClean(out bool withWafer, out string recipe) && withWafer
// && GetModule(pm.Module).GetWaferInfo(0).Status == WaferStatus.Dummy
// && GetModule(pm.Module).GetWaferInfo(0).ProcessState == EnumWaferProcessStatus.Wait)
//{
// pm.Process(recipe, true, withWafer);
// continue;
//}
if (GetModule(pm.Module).CheckWaferNeedProcess(0, pm.Module))
{
2023-03-13 17:37:55 +08:00
var wafer = GetModule(pm.Module).GetWaferInfo(0);
2023-03-03 15:42:13 +08:00
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 bool withWafer, out string recipe) && !withWafer)
//{
// pm.Process(recipe, true, withWafer);
// continue;
//}
if (!pm.IsReadyForPlace(ModuleName.TMRobot, 0))
{
pm.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0);
}
}
}
}
private void MonitorTmRobotTask()
{
if (!_tmRobot.IsAvailable)
return;
foreach (var pm in _lstPms)
{
if (pm.IsWaitTransfer(ModuleName.TMRobot))
pm.StopWaitTransfer(ModuleName.TMRobot);
}
if (_buffer.IsWaitTransfer(ModuleName.TMRobot))
_buffer.StopWaitTransfer(ModuleName.TMRobot);
if (_load.IsWaitTransfer(ModuleName.TMRobot))
_load.StopWaitTransfer(ModuleName.TMRobot);
if (_unload.IsWaitTransfer(ModuleName.TMRobot))
_unload.StopWaitTransfer(ModuleName.TMRobot);
if (!_tmRobot.IsAvailable)
return;
var act = tmRobotActions.Peek();
act.Invoke();
tmRobotActions.Enqueue(tmRobotActions.Dequeue());
}
private void MonitorWaferRobotTask()
{
foreach (var cass in _lstWaferCassettes)
{
if (cass.IsWaitTransfer(ModuleName.WaferRobot))
cass.StopWaitTransfer(ModuleName.WaferRobot);
}
if (_aligner.IsWaitTransfer(ModuleName.WaferRobot))
_aligner.StopWaitTransfer(ModuleName.WaferRobot);
if (_load.IsWaitTransfer(ModuleName.WaferRobot))
_load.StopWaitTransfer(ModuleName.WaferRobot);
if (_unload.IsWaitTransfer(ModuleName.WaferRobot))
_unload.StopWaitTransfer(ModuleName.WaferRobot);
if (!_waferRobot.IsAvailable)
return;
var act = waferRobotActions.Peek();
act.Invoke();
waferRobotActions.Enqueue(waferRobotActions.Dequeue());
}
private void MonitorTrayRobotTask()
{
if (_cassetteBL.IsWaitTransfer(ModuleName.TrayRobot))
_cassetteBL.StopWaitTransfer(ModuleName.TrayRobot);
if (_load.IsWaitTransfer(ModuleName.TrayRobot))
_load.StopWaitTransfer(ModuleName.TrayRobot);
if (!_trayRobot.IsAvailable)
{
return;
}
var act = trayRobotActions.Peek();
act.Invoke();
trayRobotActions.Enqueue(trayRobotActions.Dequeue());
}
private void MonitorTmRobotLoadPlaceTask()
{
if (!_load.IsAvailable || !_tmRobot.IsAvailable)
{
return;
}
//第二种情况 : Load腔无Tray,TMRobot上有使用次数用完的Tray
bool canPlace = _tmRobot.HasTrayAndExceedProcessCount(0) && _tmRobot.NoWafer(0) && _load.NoTray(0);
if (canPlace)
{
if (_load.IsReadyForPlace(ModuleName.TMRobot, 0))
{
if(_unload.IsInPumping)
{
return;
}
if (_tmRobot.Place(_load.Module, 0, Hand.Blade1))
{
_load.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
if (!_load.IsAvailable || !_tmRobot.IsAvailable)
{
return;
}
//第一种情况 : Load腔有Wafer需要Process,TMRobot上有使用次数未超的Tray
canPlace = _tmRobot.HasTrayAndNotExceedProcessCount(0) && _tmRobot.NoWafer(0) && _load.NoTray(0) && _load.HasWafer(0)
&& _load.CheckWaferNeedProcess(0);
if (canPlace)
{
if (_load.CheckWaferNeedProcess(0, _pm1.Module) && _tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 1)
{
return;
}
if (_load.CheckWaferNeedProcess(0, _pm2.Module) && _tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 0)
{
return;
}
if (_load.IsReadyForPlace(ModuleName.TMRobot, 0))
{
if (_unload.IsInPumping)
{
return;
}
if (_tmRobot.Place(_load.Module, 0, Hand.Blade1))
{
_load.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
private void MonitorTmRobotLoadPickTask()
{
if (!_load.IsAvailable || !_tmRobot.IsAvailable)
{
return;
}
//pick TM无Tray,需要Process,下一个位置没有Tray
bool canPick = _tmRobot.NoTray(0) && _load.CheckWaferNeedProcess(0) && !_load.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0)
&& _load.CheckWaferNextStepModuleNoTray(0);
if (canPick)
{
//需要完成组合和Purge
if (!_load.CheckWaferTrayGrouped())
{
return;
}
if (_load.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_unload.IsInPumping)
{
return;
}
if (_tmRobot.Pick(_load.Module, 0, Hand.Blade1))
{
_load.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
private void MonitorTmRobotUnLoadPlaceTask()
{
if (!_unload.IsAvailable || !_tmRobot.IsAvailable)
{
return;
}
//place Robot有Wafer,UnLoad无Tray无Wafer
bool canPlaceUnLoad = _tmRobot.HasWafer(0)
&& _tmRobot.HasTray(0)
&& _unload.NoTray(0)
&& _unload.NoWafer(0)
&& (_aligner.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0) || _unload.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0)
|| _tmRobot.CheckWaferSequenceStepDone(0));
//&& _tmRobot.GetWaferInfo(0).ProcessState == EnumWaferProcessStatus.Completed;
if (canPlaceUnLoad)
{
if (_unload.IsReadyForPlace(ModuleName.TMRobot, 0))
{
if (_tmRobot.Place(_unload.Module, 0, Hand.Blade1))
{
_unload.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
private void MonitorTmRobotUnLoadPickTask()
{
if (!_unload.IsAvailable || !_tmRobot.IsAvailable)
{
return;
}
//pick UnLoad有Tray,TM无Tray,LoadLock没有Tray,UnLoad分离完成
bool canPickUnLoad = _tmRobot.NoTray(0)
&& _tmRobot.NoWafer(0)
&& _unload.HasTray(0)
&& _load.NoTray(0);
//&& _unload.GetWaferInfo(0).ProcessState == EnumWaferProcessStatus.Completed;
if (canPickUnLoad)
{
//需要UnLoad把石墨盘和Wafer分离完成
if (!_unload.CheckWaferTraySeparated())
{
return;
}
if (_unload.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(_unload.Module, 0, Hand.Blade1))
{
_unload.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
private void MonitorTmRobotBufferPlaceTask()
{
if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
{
return;
}
//place Buffer位置没有Tray,Robot有Wafer,下一步骤是Buffer
bool canPalce = _tmRobot.HasWafer(0) && _tmRobot.HasTray(0) && _buffer.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0);
if (canPalce)
{
SlotItem bufferEmptySlot = null;
if ((_tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 0)
&& _tmRobot.CheckWaferNeedProcess(0, _pm1.Module)
&& _buffer.NoTray(0)
&& _buffer.NoWafer(0))
{
bufferEmptySlot = new SlotItem(ModuleName.Buffer, 0);
}
else if ((_tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 1)
&& _tmRobot.CheckWaferNeedProcess(0, _pm2.Module)
&& _buffer.NoTray(1)
&& _buffer.NoWafer(1))
{
bufferEmptySlot = new SlotItem(ModuleName.Buffer, 1);
}
if (bufferEmptySlot != null)
{
if (_buffer.IsReadyForPlace(ModuleName.TMRobot, bufferEmptySlot.Slot))
{
if (_tmRobot.Place(_buffer.Module, bufferEmptySlot.Slot, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
{
return;
}
//place 完成工艺后的Tray放入Buffer中
canPalce = _tmRobot.HasTray(0) && _tmRobot.NoWafer(0);
if (canPalce)
{
if (_tmRobot.HasTrayAndExceedProcessCount(0) && _load.NoTray(0))
return;
SlotItem bufferEmptySlot = null;
if (_tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 0 && _buffer.NoTray(0) && _buffer.NoWafer(0)
&& !_load.CheckWaferNeedProcess(0, _pm1.Module)
&& !_waferRobot.CheckWaferNeedProcess(0, _pm1.Module)
&& !_aligner.CheckWaferNeedProcess(0, _pm1.Module))
{
bufferEmptySlot = new SlotItem(ModuleName.Buffer, 0);
}
else if (_tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 1 && _buffer.NoTray(1) && _buffer.NoWafer(1)
&& !_load.CheckWaferNeedProcess(0, _pm2.Module)
&& !_waferRobot.CheckWaferNeedProcess(0, _pm2.Module)
&& !_aligner.CheckWaferNeedProcess(0, _pm2.Module))
{
bufferEmptySlot = new SlotItem(ModuleName.Buffer, 1);
}
if (bufferEmptySlot != null)
{
if (_buffer.IsReadyForPlace(ModuleName.TMRobot, bufferEmptySlot.Slot))
{
if (_tmRobot.Place(_buffer.Module, bufferEmptySlot.Slot, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
{
return;
}
//place load有wafer有tray要process,需放到buffer3进行躲避
canPalce = _tmRobot.HasTray(0) && _tmRobot.NoWafer(0) && _buffer.NoTray(2) && _buffer.NoWafer(2);
if (canPalce)
{
if (_tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 0
&& ((_load.HasTray(0) && _load.HasWafer(0) && _load.CheckWaferNeedProcess(0, _pm1.Module))
|| (_buffer.HasTray(0) && _buffer.HasWafer(0))
))
{
if (_buffer.IsReadyForPlace(ModuleName.TMRobot, 2))
{
if (_tmRobot.Place(_buffer.Module, 2, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
else if (_tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 1
&& ((_load.HasTray(0) && _load.HasWafer(0) && _load.CheckWaferNeedProcess(0, _pm2.Module))
|| (_buffer.HasTray(1) && _buffer.HasWafer(1))
))
{
if (_buffer.IsReadyForPlace(ModuleName.TMRobot, 2))
{
if (_tmRobot.Place(_buffer.Module, 2, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
}
private void MonitorTmRobotBufferPickTask()
{
if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
{
return;
}
MonitorTmRobotBuffer1PickTask();
MonitorTmRobotBuffer2PickTask();
MonitorTmRobotBuffer3PickTask();
}
private void MonitorTmRobotBuffer1PickTask()
{
if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
{
return;
}
//第一种情况:Buffer1的Wafer需要去PM1腔工艺
bool canPick = _tmRobot.NoTray(0) && _buffer.HasTray(0) && _buffer.HasWafer(0) && !_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, 0);
if (canPick)
{
if (_pm1.CheckWaferNextStepIsThis(ModuleName.Buffer, 0))
{
if (!_pm1.IsAvailable || _pm1.HasTray(0) || _pm1.HasWafer(0) || !_pm1.IsReadyForPlace(ModuleName.TMRobot, 0) ||
!_pm1.CheckBufferToPMTemp())
return;
if (_buffer.CheckWaferNextStepModuleNoTray(0))
{
if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(_buffer.Module, 0, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
}
if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
{
return;
}
//第二种情况:工艺开始时,如果Buffer中有Tray时,优先取Buffer中的Tray,而不是Cassette中Tray
canPick = _tmRobot.NoTray(0)
&& _load.IsAvailable
&& _load.IsReadyForPlace(ModuleName.TMRobot, 0)
&& _load.NoTray(0)
&& _load.HasWafer(0)
&& _load.CheckWaferNeedProcess(0,ModuleName.PM1);
if (canPick)
{
//取Tray前判断Unload是否IsInPumping,否则就会发生TMRobot有Tray
//在等Unload Pumping完成的情况
if(_unload.IsInPumping)
{
return;
}
if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(_buffer.Module, 0, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
private void MonitorTmRobotBuffer2PickTask()
{
if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
{
return;
}
//第一种情况:Buffer2的Wafer需要去PM2腔工艺
bool canPick = _tmRobot.NoTray(0) && _buffer.HasTray(1) && _buffer.HasWafer(1) && !_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, 1);
if (canPick)
{
if (_pm2.CheckWaferNextStepIsThis(ModuleName.Buffer, 1))
{
if (!_pm2.IsAvailable || _pm2.HasTray(0) || _pm2.HasWafer(0) || !_pm2.IsReadyForPlace(ModuleName.TMRobot, 0) ||
!_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;
}
}
}
}
}
if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
{
return;
}
//第二种情况:工艺开始时,如果Buffer中有Tray时,优先取Buffer中的Tray,而不是Cassette中Tray
canPick = _tmRobot.NoTray(0)
&& _buffer.HasTray(1)
&& _buffer.NoWafer(1)
&& _load.IsAvailable
&& _load.IsReadyForPlace(ModuleName.TMRobot, 0)
&& _load.NoTray(0)
&& _load.HasWafer(0)
&& _load.CheckWaferNeedProcess(0, ModuleName.PM2);
if (canPick)
{
//取Tray前判断Unload是否IsInPumping,否则就会发生TMRobot有Tray
//在等Unload Pumping完成的情况
if (_unload.IsInPumping)
{
return;
}
if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(_buffer.Module, 1, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
private void MonitorTmRobotBuffer3PickTask()
{
if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
{
return;
}
bool canPick = _tmRobot.NoTray(0) && _buffer.HasTray(2);
if (canPick)
{
if (_buffer.GetWaferInfo(2).TrayOriginSlot % 2 == 0)
{
//第一种情况 : buffer0位置没有trayload有tray但不是去PM1的
if (_buffer.NoTray(0) && _load.HasTray(0) && !_load.CheckWaferNeedProcess(0, _pm1.Module))
{
if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(_buffer.Module, 2, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
//第二种情况 : buffer0位置没有tray,load也没有tray,并且没有wafer,或者有wafer但是去PM1的
else if (_buffer.NoTray(0) && _load.NoTray(0) && (_load.CheckWaferNeedProcess(0, _pm1.Module) || _load.NoWafer(0)))
{
if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(_buffer.Module, 2, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
//第三种情况 :buffer0位置有tray但是pm1没有tray
else if (_buffer.HasTray(0) && !_buffer.CheckWaferNeedProcess(0, _pm1.Module) && _pm1.NoTray(0) && _pm1.NoWafer(0))
{
if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(_buffer.Module, 2, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
if (_buffer.GetWaferInfo(2).TrayOriginSlot % 2 == 1)
{
//第一种情况 : buffer1位置没有trayload有tray但不是去PM2的
if (_buffer.NoTray(1) && _load.HasTray(0) && !_load.CheckWaferNeedProcess(0, _pm2.Module))
{
if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(_buffer.Module, 2, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
//第二种情况 : buffer1位置没有trayload也没有tray没有wafer或者有wafer但是去PM2的
else if (_buffer.NoTray(1) && _load.NoTray(0) && (_load.CheckWaferNeedProcess(0, _pm2.Module) || _load.NoWafer(0)))
{
if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(_buffer.Module, 2, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
//第三种情况 : buffer1位置有tray但是pm2没有tray
else if (_buffer.HasTray(1) && !_buffer.CheckWaferNeedProcess(1, _pm2.Module) && _pm2.NoTray(0) && _pm2.NoWafer(0))
{
if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(_buffer.Module, 2, Hand.Blade1))
{
_buffer.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
}
}
private void MonitorTmRobotPMPlaceTask()
{
if (!_tmRobot.IsAvailable)
{
return;
}
//第二种情况 : TMRobot有Tray没有Wafer,对应Buffer有Tray,需放PM存盘
bool canPlaceNoProcess = _tmRobot.NoWafer(0) && _tmRobot.HasTrayAndNotExceedProcessCount(0);
if (canPlaceNoProcess)
{
foreach (var pm in _lstPms)
{
int bufferIndex = 0;
if (pm == _pm2)
{
bufferIndex = 1;
}
if (_tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == bufferIndex
&& _buffer.HasTray(bufferIndex)
&& _buffer.NoWafer(bufferIndex)
&& !_buffer.CheckWaferNeedProcess(bufferIndex, pm.Module)
&& pm.IsAvailable
&& pm.NoTray(0)
&& pm.NoWafer(0)
&& pm.CheckTempBelow900()
&& pm.IsReadyForPlace(ModuleName.TMRobot, 0))
{
if (_tmRobot.Place(pm.Module, 0, Hand.Blade1))
{
pm.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
if (!_tmRobot.IsAvailable)
{
return;
}
//第一种情况 : TMRobot有Wafer并且需要Process
bool canPlace = _tmRobot.HasWafer(0) && _tmRobot.HasTray(0) && _tmRobot.CheckWaferNeedProcess(0);
if (canPlace)
{
foreach (var pm in _lstPms)
{
if (!pm.IsAvailable
|| !GetModule(pm.Module).NoWafer(0)
|| !pm.IsReadyForPlace(ModuleName.TMRobot, 0)
|| !pm.CheckTempBelow900())
continue;
bool blade0Place = _tmRobot.HasWafer(0) && _tmRobot.CheckWaferNeedProcess(0, pm.Module) && pm.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0);
if (blade0Place)
{
Hand placeBlade = Hand.Blade1;
if (_tmRobot.Place(pm.Module, 0, placeBlade))
{
pm.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
}
private void MonitorTmRobotPMPickTask()
{
if (!_tmRobot.IsAvailable)
{
return;
}
//第一种情况 : Wafer工艺结束后需取出
if (_tmRobot.NoWafer(0) && _tmRobot.NoTray(0))
{
//Wafer取出后只能去Unload冷却Buffer3有其他用途,冷却取消
if (_unload.HasWafer(0) || _unload.HasTray(0) || !_unload.IsReadyForPlace(ModuleName.TMRobot, 0) || !_unload.IsAvailable)
{
return;
}
Hand pickBlade = Hand.Blade1;
ModuleName pickPm = ModuleName.System;
bool canPickPM1 = false;
bool canPickPM2 = false;
if(_pm1.IsAvailable && _pm1.HasWafer(0) && _pm1.HasTray(0) && !_pm1.CheckWaferNeedProcess(0)
2023-04-04 11:08:53 +08:00
&& _pm1.CheckPMToTMRobotTemp())
2023-03-03 15:42:13 +08:00
{
canPickPM1 = true;
}
if (_pm2.IsAvailable && _pm2.HasWafer(0) && _pm2.HasTray(0) && !_pm2.CheckWaferNeedProcess(0)
2023-04-04 11:08:53 +08:00
&& _pm2.CheckPMToTMRobotTemp())
2023-03-03 15:42:13 +08:00
{
canPickPM2 = true;
}
if (canPickPM1 && !canPickPM2)
{
pickPm = ModuleName.PM1;
}
else if (!canPickPM1 && canPickPM2)
{
pickPm = ModuleName.PM2;
}
else if (canPickPM1 && canPickPM2)
{
string pm1ProcessTime = SC.GetStringValue("PM.PM1.PostProcessEndTime");
string pm2ProcessTime = SC.GetStringValue("PM.PM2.PostProcessEndTime");
if (DateTime.TryParse(pm1ProcessTime, out DateTime dtPM1)
&& DateTime.TryParse(pm2ProcessTime, out DateTime dtPM2))
{
pickPm = dtPM1.CompareTo(dtPM2) <= 0 ? ModuleName.PM1 : ModuleName.PM2;
}
else
{
pickPm = ModuleName.PM1;
}
}
if (pickPm != ModuleName.System)
{
SchedulerModule pm = GetModule(pickPm.ToString());
if (pm.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(pm.Module, 0, pickBlade))
{
pm.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
if (!_tmRobot.IsAvailable)
{
return;
}
//第二种情况 : PM腔有Tray没Wafer需取出到Buffer3
if (_tmRobot.NoWafer(0) && _tmRobot.NoTray(0))
{
Hand pickBlade = Hand.Blade1;
foreach (var pm in _lstPms)
{
//增加温度低于900才能Pick的限制
if (!pm.IsAvailable
|| pm.HasWafer(0)
|| pm.NoTray(0)
|| GetModule(pm.Module).CheckWaferNeedProcess(0, pm.Module)
|| !pm.CheckTempBelow900()
|| _buffer.HasTray(2)
|| _buffer.HasWafer(2))
continue;
//如果对应的Buffer1/2有没超次数的Tray和无Wafer,则不取
int bufferIndex = 0;
if (pm == _pm2)
{
bufferIndex = 1;
}
if (_buffer.NoWafer(bufferIndex) && _buffer.HasTrayAndNotExceedProcessCount(bufferIndex))
{
return;
}
if (pm.IsReadyForPick(ModuleName.TMRobot, 0))
{
if (_tmRobot.Pick(pm.Module, 0, pickBlade))
{
pm.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
}
private void MonitorWaferRobotLoadPlaceTask()
{
if (!_waferRobot.IsAvailable || !_load.IsAvailable)
{
return;
}
//place Load没有Wafer,没有Tray,Robot有Wafer,步骤没有完成,
//下一步不是Aligner (其它:SlitValve都关了,大气)
bool canPlace = _waferRobot.HasWafer(0)
&& _load.NoWafer(0)
&& _load.NoTray(0)
&& _waferRobot.GetWaferInfo(0).Status != WaferStatus.Dummy
&& !_aligner.CheckWaferNextStepIsThis(ModuleName.WaferRobot, 0)
&& _waferRobot.CheckWaferNeedProcess(0);
if (canPlace)
{
if (_load.IsReadyForPlace(ModuleName.WaferRobot, 0))
{
if (_waferRobot.Place(_load.Module, 0, Hand.Blade1))
{
_load.WaitTransfer(ModuleName.WaferRobot);
return;
}
}
}
}
private void MonitorWaferRobotUnLoadPickTask()
{
if (!_waferRobot.IsAvailable || !_unload.IsAvailable)
{
return;
}
//pick UnLoad有Wafer没有Tray,Robot没有Wafer,步骤都完成了或者下一步的模块没有片子 (其它:UnLoad 夹爪夹住,顶针下降,SlitValve都关了,大气)
bool canPick = _waferRobot.NoWafer(0)
&& _unload.HasWafer(0)
&& _unload.NoTray(0)
&& (_unload.CheckWaferNextStepModuleNoWafer(0) || _unload.CheckWaferSequenceStepDone(0))
&& _unload.GetWaferInfo(0).Status != WaferStatus.Dummy;
if (canPick)
{
//下一步是Aligner并且Aligner上不允许有片子
if (_aligner.CheckWaferNextStepIsThis(ModuleName.UnLoad, 0))
{
if (_aligner.HasWafer(0))
{
return;
}
}
if (_unload.IsReadyForPick(ModuleName.WaferRobot, 0))
{
if (_waferRobot.Pick(_unload.Module, 0, Hand.Blade1))
{
_unload.WaitTransfer(ModuleName.WaferRobot);
return;
}
}
}
}
private void MonitorWaferRobotAlignerPlaceTask()
{
if (!_waferRobot.IsAvailable || !_aligner.IsAvailable)
{
return;
}
//place 任务还没完成,下一步是Aligner,Robot有片子,Aligner没片子
bool canPlaceAligner = _aligner.NoWafer(0)
&& _waferRobot.HasWafer(0)
&& (_aligner.CheckWaferNextStepIsThis(ModuleName.WaferRobot, 0) || _waferRobot.CheckWaferSequenceStepDone(0))
&& _waferRobot.GetWaferInfo(0).Status != WaferStatus.Dummy;
if (canPlaceAligner)
{
if (_aligner.IsReadyForPlace(ModuleName.WaferRobot, 0))
{
if (_waferRobot.Place(_aligner.Module, 0, Hand.Blade1))
{
_aligner.WaitTransfer(ModuleName.WaferRobot);
return;
}
}
}
}
private void MonitorWaferRobotAlignerPickTask()
{
if (!_waferRobot.IsAvailable || !_aligner.IsAvailable)
{
return;
}
//pick Aligner wafer to Load
bool canPickAligner = _aligner.HasWafer(0)
&& _waferRobot.NoWafer(0)
&& _aligner.GetWaferInfo(0).Status != WaferStatus.Dummy
&& !_aligner.CheckWaferNextStepIsThis(ModuleName.Aligner, 0)
&& _load.CheckWaferNextStepIsThis(ModuleName.Aligner, 0)
&& _load.IsReadyForPlace(ModuleName.WaferRobot, 0)
&& _load.IsAvailable;
if (canPickAligner)
{
//需要运行工艺,Load不能有片子Load不能有Tray
if (_aligner.CheckWaferNeedProcess(0))
{
if (_load.HasWafer(0)
|| _load.HasTray(0)
|| _tmRobot.HasTrayAndExceedProcessCount(0)
|| _buffer.HasTrayAndExceedProcessCount(0)
|| _buffer.HasTrayAndExceedProcessCount(1)
|| _buffer.HasTrayAndExceedProcessCount(2))
{
return;
}
}
if (_aligner.IsReadyForPick(ModuleName.WaferRobot, 0))
{
if (_waferRobot.Pick(_aligner.Module, 0, Hand.Blade1))
{
_aligner.WaitTransfer(ModuleName.WaferRobot);
return;
}
}
}
//pick Aligner wafer to Cassette
bool canPick = _aligner.HasWafer(0)
&& _waferRobot.NoWafer(0)
&& _aligner.GetWaferInfo(0).Status != WaferStatus.Dummy
&& !_aligner.CheckWaferNextStepIsThis(ModuleName.Aligner, 0)
&& _aligner.CheckWaferSequenceStepDone(0);
if (canPick)
{
if (_aligner.IsReadyForPick(ModuleName.WaferRobot, 0))
{
if (_waferRobot.Pick(_aligner.Module, 0, Hand.Blade1))
{
_aligner.WaitTransfer(ModuleName.WaferRobot);
return;
}
}
}
}
private void MonitorWaferRobotCassettePlaceTask()
{
if (!_waferRobot.IsAvailable)
{
return;
}
//place 任务完成了,Robot有片子,Cassette没有片子
bool canPlaceCassette = _waferRobot.HasWafer(0)
&& _waferRobot.GetWaferInfo(0).Status != WaferStatus.Dummy
&& _waferRobot.CheckWaferSequenceStepDone(0);
if (canPlaceCassette)
{
2023-03-13 17:37:55 +08:00
var wafer = _waferRobot.GetWaferInfo(0);
2023-03-03 15:42:13 +08:00
if (GetWaferReturnedCassette((ModuleName)wafer.OriginStation) == ModuleName.CassAL)
{
if (_cassetteAL.IsAvailable && _cassetteAL.IsReadyForPlace(ModuleName.WaferRobot, wafer.OriginSlot))
{
if (_waferRobot.Place(_cassetteAL.Module, wafer.OriginSlot, Hand.Blade1))
{
_cassetteAL.WaitTransfer(ModuleName.WaferRobot);
return;
}
}
}
else if (GetWaferReturnedCassette((ModuleName)wafer.OriginStation) == ModuleName.CassAR)
{
if (_cassetteAR.IsAvailable && _cassetteAR.IsReadyForPlace(ModuleName.WaferRobot, wafer.OriginSlot))
{
if (_waferRobot.Place(_cassetteAR.Module, wafer.OriginSlot, Hand.Blade1))
{
_cassetteAR.WaitTransfer(ModuleName.WaferRobot);
return;
}
}
}
}
}
private void MonitorWaferRobotCassettePickTask()
{
if (!_waferRobot.IsAvailable)
{
return;
}
//pick Robot没有片子,下一步的模块没有片子
bool canPick = _waferRobot.NoWafer(0);
SlotItem position = GetWaferInJobQueue();
if (canPick && position != null)
{
//下一步是Aligner并且Aligner上不允许有片子
if (_aligner.CheckWaferNextStepIsThis(position.Module, position.Slot) && _aligner.HasWafer(0))
{
return;
}
//如果Load腔有Wafer或者Load/TMRobot/Buffer有已用完次数的Tray,
//则WaferRobot不能从Cassette取Wafer
else if ( _load.HasWafer(0)
|| !_load.IsAvailable
|| !_load.IsReadyForPlace(ModuleName.WaferRobot,0)
|| _load.HasTrayAndExceedProcessCount(0)
|| _tmRobot.HasTrayAndExceedProcessCount(0))
{
return;
}
//超过可以运行的石墨盘最大数
if (GetRunWaferCount() >= _maxTrayCount)
{
return;
}
//每个腔超过2个Wafer则不在取Wafer
if(CheckWaferNeedProcess(position.Module,position.Slot,_pm1.Module))
{
if (GetRunWaferCount(_pm1.Module) >= 2)
{
return;
}
}
if(CheckWaferNeedProcess(position.Module, position.Slot, _pm2.Module))
{
if (GetRunWaferCount(_pm2.Module) >= 2)
{
return;
}
}
if (position.Module == ModuleName.CassAL)
{
if (_cassetteAL.IsAvailable && _cassetteAL.IsReadyForPick(ModuleName.WaferRobot, 0))
{
if (_waferRobot.Pick(position.Module, position.Slot, Hand.Blade1))
{
_cassetteAL.WaitTransfer(ModuleName.WaferRobot);
return;
}
}
}
else if (position.Module == ModuleName.CassAR)
{
if (_cassetteAR.IsAvailable && _cassetteAR.IsReadyForPick(ModuleName.WaferRobot, 0))
{
if (_waferRobot.Pick(position.Module, position.Slot, Hand.Blade1))
{
_cassetteAR.WaitTransfer(ModuleName.WaferRobot);
return;
}
}
}
}
}
private void MonitorTrayRobotLoadPlaceTask()
{
if (!_trayRobot.IsAvailable || !_load.IsAvailable)
{
return;
}
if (GetCurrentTrayCount() >= _maxTrayCount)
{
return;
}
//place Load没有Tray,有Wafer未完成
bool canPlace = _load.NoTray(0)
&& _trayRobot.HasTrayAndNotExceedProcessCount(0)
&& _load.HasWafer(0)
&& _load.CheckWaferNeedProcess(0);
if (canPlace)
{
if ( _trayRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 0 && _load.CheckWaferNeedProcess(0,_pm2.Module))
{
return;
}
if ( _trayRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 1 && _load.CheckWaferNeedProcess(0,_pm1.Module))
{
return;
}
//TMRobot有Tray无Wafer也不能放
if (_tmRobot.NoWafer(0) && _tmRobot.HasTray(0))
{
return;
}
if (_load.IsReadyForPlace(ModuleName.TrayRobot, 0))
{
if (_trayRobot.Place(_load.Module, 0, Hand.Blade1))
{
_load.WaitTransfer(ModuleName.TrayRobot);
return;
}
}
}
}
private void MonitorTrayRobotLoadPickTask()
{
if (!_trayRobot.IsAvailable || !_load.IsAvailable)
{
return;
}
//pick Load有Tray,且Tray次数已使用完
bool canPick = _load.HasTrayAndExceedProcessCount(0);
if (canPick)
{
SlotItem emptyTraySlot = GetTrayOrignSlot(ModuleName.LoadLock, 0);// GetEmptyTraySlot(13); //先取Wafer再取石墨盘
if (emptyTraySlot != null && _load.HasTrayAndExceedProcessCount(0))
{
if (_load.IsReadyForPick(ModuleName.TrayRobot, 0))
{
if (_trayRobot.Pick(_load.Module, 0, Hand.Blade1))
{
_load.WaitTransfer(ModuleName.TrayRobot);
return;
}
}
}
}
}
private void MonitorTrayRobotCassettePlaceTask()
{
if (!_trayRobot.IsAvailable || !_cassetteBL.IsAvailable)
{
return;
}
//place Robot有盘 其它逻辑跟Load的Pick一致
bool canPlace = _trayRobot.HasTrayAndExceedProcessCount(0)
|| _load.HasTray(0)
|| (GetWaferInJobQueue() == null && _aligner.NoWafer(0) && _waferRobot.NoWafer(0) && _load.NoWafer(0));
if (canPlace)
{
SlotItem slotItem = GetTrayOrignSlot(ModuleName.TrayRobot, 0);
if (slotItem != null)
{
if (_cassetteBL.IsReadyForPlace(ModuleName.TrayRobot, slotItem.Slot))
{
if (_trayRobot.Place(slotItem.Module, slotItem.Slot, Hand.Blade1))
{
_cassetteBL.WaitTransfer(ModuleName.TrayRobot);
return;
}
}
}
}
}
private void MonitorTrayRobotCassettePickTask()
{
if (!_trayRobot.IsAvailable || !_cassetteBL.IsAvailable)
{
return;
}
//各个腔体运行的石墨盘总数小于设定值
if (GetCurrentTrayCount() >= _maxTrayCount)
{
return;
}
foreach (var pm in _lstPms)
{
if(_load.HasWafer(0) && _load.CheckWaferNeedProcess(0, pm.Module) && _load.NoTray(0) && _trayRobot.NoTray(0))
{
if(CheckLoadWaferNeedCassetteTray(pm.Module))
{
int usedForWhichPM = 0;
if(pm == _pm2)
{
usedForWhichPM = 1;
}
SlotItem slotItem = GetTraySlot(8, usedForWhichPM);
if (slotItem != null)
{
if (_cassetteBL.IsReadyForPick(ModuleName.TrayRobot, slotItem.Slot))
{
if (_trayRobot.Pick(slotItem.Module, slotItem.Slot, Hand.Blade1))
{
_cassetteBL.WaitTransfer(ModuleName.TrayRobot);
return;
}
}
}
}
}
}
}
private bool CheckLoadWaferNeedCassetteTray(ModuleName pm)
{
if (pm == ModuleName.PM1)
{
if ((_buffer.HasTray(0) && _buffer.NoWafer(0))
|| (_pm1.HasTray(0) && _pm1.NoWafer(0)))
{
return false;
}
}
if (pm == ModuleName.PM2)
{
if ((_buffer.HasTray(1) && _buffer.NoWafer(1))
|| (_pm2.HasTray(0) && _pm2.NoWafer(0)))
{
return false;
}
}
List<Tuple<ModuleName, int>> modules = new List<Tuple<ModuleName, int>>()
{
new Tuple<ModuleName, int>(ModuleName.Buffer,0),
new Tuple<ModuleName, int>(ModuleName.Buffer,1),
new Tuple<ModuleName, int>(ModuleName.Buffer,2),
new Tuple<ModuleName, int>(ModuleName.TMRobot,0),
new Tuple<ModuleName, int>(ModuleName.PM1,0),
new Tuple<ModuleName, int>(ModuleName.PM2,0),
};
foreach (var module in modules)
{
if (CheckHasTrayAndNoWaferByModule(module.Item1, module.Item2, pm))
{
return false;
}
}
return true;
}
/// <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;
2023-03-13 17:37:55 +08:00
var wafer = GetModule(module).GetWaferInfo(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;
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;
2023-03-13 17:37:55 +08:00
var wafer = GetModule(module).GetWaferInfo(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 - 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;
}
private bool GetWaferSequenceCoolingTime(ModuleName module, int slot, out int coolingTime)
{
coolingTime = 0;
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;
if (!int.TryParse(wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter["CoolingTime"].ToString(),
out coolingTime))
{
coolingTime = 0;
//coolingTime = SC.GetValue<int>("Unload.DefaultCoolingTime");
//EV.PostWarningLog("Scheduler", $"Sequence step Unload cooling time is not valid, instead with the SC default value {coolingTime} seconds");
return false;
}
return true;
}
private bool CheckHasTrayAndNoWafer(List<Tuple<ModuleName, int>> needCheckPositions)
{
foreach (var positionTuple in needCheckPositions)
{
var module = GetModule(positionTuple.Item1);
if (module.HasTray(positionTuple.Item2) && module.NoWafer(positionTuple.Item2))
{
return true;
}
}
return false;
}
private bool CheckHasTrayAndNoWaferByModule(ModuleName moduleName, int slot,ModuleName pmModule)
{
var module = GetModule(moduleName);
if((module.GetWaferInfo(slot).TrayOriginSlot % 2 == 0 && pmModule == ModuleName.PM1)
|| (module.GetWaferInfo(slot).TrayOriginSlot % 2 == 1 && pmModule == ModuleName.PM2))
{
if (module.HasTray(slot) && module.NoWafer(slot))
{
return true;
}
}
return false;
}
private bool CheckTrayExhausted()
{
return !(_buffer.HasTrayAndNotExceedProcessCount(0)
| _buffer.HasTrayAndNotExceedProcessCount(1)
| _buffer.HasTrayAndNotExceedProcessCount(2)
| _cassetteBL.HasTrayAndNotExceedProcessCount(0)
| _cassetteBL.HasTrayAndNotExceedProcessCount(1)
| _cassetteBL.HasTrayAndNotExceedProcessCount(2)
| _cassetteBL.HasTrayAndNotExceedProcessCount(3)
| _cassetteBL.HasTrayAndNotExceedProcessCount(4)
| _cassetteBL.HasTrayAndNotExceedProcessCount(5)
| _cassetteBL.HasTrayAndNotExceedProcessCount(6)
| _cassetteBL.HasTrayAndNotExceedProcessCount(7)
| _load.HasTrayAndNotExceedProcessCount(0)
| _unload.HasTrayAndNotExceedProcessCount(0)
| _tmRobot.HasTrayAndNotExceedProcessCount(0)
| _trayRobot.HasTrayAndNotExceedProcessCount(0)
| _pm1.HasTrayAndNotExceedProcessCount(0)
| _pm2.HasTrayAndNotExceedProcessCount(0));
}
public bool CheckBufferWaferHasJob()
{
2023-03-13 17:37:55 +08:00
var wafer = _buffer.GetWaferInfo(0);
2023-03-03 15:42:13 +08:00
if (wafer.IsEmpty)
{
return false;
}
if (wafer.ProcessJob == null)
{
return false;
}
ProcessJobInfo pj = _lstProcessJobs.Find(x => x.InnerId == wafer.ProcessJob.InnerId);
if (pj == null)
{
return false;
}
return true;
}
public bool CheckWaferProcessModuleIsAvailable(ModuleName waferModule, int waferSlot)
{
2023-03-13 17:37:55 +08:00
var wafer = GetModule(waferModule).GetWaferInfo(waferSlot);
2023-03-03 15:42:13 +08:00
if (wafer.IsEmpty)
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 bool _, out string _))
return true;
}
}
return false;
}
private SlotItem GetWaferInJobQueue()
{
List<Tuple<ModuleName, int>> processingWafers = new List<Tuple<ModuleName, int>>();
foreach (var cj in _lstControlJobs)
{
if (cj.State == EnumControlJobState.Executing)
{
foreach (var pj in _lstProcessJobs)
{
if (pj.ControlJobName == cj.Name && pj.State == EnumProcessJobState.Processing)
{
foreach (var pjSlotWafer in pj.SlotWafers)
{
if (pjSlotWafer.Item1 == ModuleName.CassAL || pjSlotWafer.Item1 == ModuleName.CassAR)
{
processingWafers.Add(pjSlotWafer);
}
}
}
}
}
}
if (processingWafers.Count > 0)
{
processingWafers = processingWafers.OrderBy(x => x.Item1).ThenBy(x => x.Item2).ToList();
if (SC.GetValue<bool>("System.Scheduler.IsRunInParallelMode"))
{
return SortByParallelMode(processingWafers);
}
else
{
return SortBySerialMode(processingWafers);
}
}
return null;
}
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);
}
private SlotItem GetTraySlot(int slotCount, int usedForWhichPM)
{
foreach (var cj in _lstControlJobs)
{
if (cj.State == EnumControlJobState.Executing)
{
for (int i = 0; i < slotCount; i++)
{
if (_cassetteBL.HasTrayAndNotExceedProcessCount(i) && i % 2 == usedForWhichPM)
{
return new SlotItem(ModuleName.CassBL, i);
}
}
}
}
return null;
}
private SlotItem GetTrayOrignSlot(ModuleName module, int slot)
{
2023-03-13 17:37:55 +08:00
var wafer = GetModule(module).GetWaferInfo(slot);
2023-03-03 15:42:13 +08:00
if (wafer != null && GetModule(module).HasTray(slot) && _cassetteBL.NoTray(wafer.TrayOriginSlot))
{
return new SlotItem(ModuleName.CassBL, wafer.TrayOriginSlot);
}
return null;
}
//private SlotItem GetEmptyTraySlot(int slotCount)
//{
// foreach (var cj in _lstControlJobs)
// {
// if (cj.State == EnumControlJobState.Executing)
// {
// for (int i = 0; i < slotCount; i++)
// {
//if (_cassetteBL.NoTray(i))
// {
// return new SlotItem(ModuleName.CassBL, i);
// }
// }
// }
// }
// return null;
//}
///// <summary>
///// 获取空位置
///// </summary>
///// <param name="isHeat"></param>
///// <returns></returns>
//private SlotItem GetEmptyBufferSlot(WaferInfo wafer)
//{
// foreach (var cj in _lstControlJobs)
// {
// if (cj.State == EnumControlJobState.Executing)
// {
// string strSots = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter["SlotSelection"].ToString();
// if (strSots == null)
// {
// return null;
// }
// string[] slots = strSots.Split(',');
// for (int i = 0; i < slots.Length; i++)
// {
// int slot = 0;
// if (Int32.TryParse(slots[i], out slot))
// {
// if (_buffer.NoTray(slot - 1))
// {
// return new SlotItem(ModuleName.Buffer, slot - 1);
// }
// }
// }
// }
// }
// return null;
//}
/// <summary>
/// 获取各个模块的Wafer总数量
/// </summary>
/// <returns></returns>
private int GetRunWaferCount()
{
int waferCount = 0;
if (_load.HasWafer(0))
{
waferCount++;
}
if (_unload.HasWafer(0))
{
waferCount++;
}
if (_tmRobot.HasWafer(0))
{
waferCount++;
}
foreach (SchedulerPM pm in _lstPms)
{
if (GetModule(pm.Module).HasWafer(0))
{
waferCount++;
}
}
for (int i = 0; i < 3; i++)
{
if (_buffer.HasWafer(i))
{
waferCount++;
}
}
return waferCount;
}
private int GetRunWaferCount(ModuleName processIn)
{
int waferCount = 0;
if (_load.HasWafer(0) && (_load.CheckWaferNeedProcess(0, processIn) || _load.GetWaferInfo(0).SubstHists.Select(x => x.locationID).Contains(processIn.ToString())))
{
waferCount++;
}
if (_unload.HasWafer(0) && (_unload.CheckWaferNeedProcess(0, processIn) || _unload.GetWaferInfo(0).SubstHists.Select(x => x.locationID).Contains(processIn.ToString())))
{
waferCount++;
}
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 (int 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;
}
private int GetCurrentTrayCount()
{
int trayCount = 0;
if (_load.HasTray(0))
{
trayCount++;
}
if (_unload.HasTray(0))
{
trayCount++;
}
if (_tmRobot.HasTray(0))
{
trayCount++;
}
foreach (SchedulerPM pm in _lstPms)
{
if (GetModule(pm.Module).HasTray(0))
{
trayCount++;
}
}
for (int i = 0; i < 3; i++)
{
if (_buffer.HasTray(i))
{
trayCount++;
}
}
return trayCount;
}
private int GetCurrentWaferCount()
{
int waferCountDiv = 0;
int cassWaferCount = 0;
foreach (var cj in _lstControlJobs)
{
if (cj.State == EnumControlJobState.Executing)
{
foreach (var pj in _lstProcessJobs)
{
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;
}
public Result MonitorModuleError()
{
bool isModuleError = false;
bool[] isPMError = new bool[2];
for (int i = 0; i < isPMError.Length; i++)
{
isPMError[i] = false;
}
if (_tmRobot.IsError)
isModuleError = true;
for (int i = 0; i < _lstPms.Count; i++) // PM出错不影响其他腔体的传片
{
if (_lstPms[i].IsError)
isPMError[i] = true;
}
if (isModuleError && !_isModuleErrorPrevious)
{
}
else if (!isModuleError && _isModuleErrorPrevious)
{
Reset();
}
for (int 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 (_lstControlJobs.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 (_aligner.HasWafer(0))
{
reason = $"Aligner have wafer!";
EV.PostWarningLog(LogSource, reason);
return true;
}
if (_waferRobot.HasWafer(0))
{
reason = $"WaferRobot have wafer!";
EV.PostWarningLog(LogSource, reason);
return true;
}
if (_load.HasWafer(0))
{
reason = $"Load have wafer!";
EV.PostWarningLog(LogSource, reason);
return true;
}
if (_load.HasTray(0))
{
reason = $"Load have Tray!";
EV.PostWarningLog(LogSource, reason);
return true;
}
if (_unload.HasWafer(0))
{
reason = $"UnLoad have wafer!";
EV.PostWarningLog(LogSource, reason);
return true;
}
if (_unload.HasTray(0))
{
reason = $"UnLoad have Tray!";
EV.PostWarningLog(LogSource, reason);
return true;
}
return false;
}
}
private bool CheckWaferNeedProcess(ModuleName module, 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 == null)
{
return false;
}
if (wafer.IsEmpty)
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;
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;
}
}
}