Sic03-8inch/SicRT/Equipments/AutoTransfer.cs

3821 lines
141 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

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

using System;
using System.Collections.Generic;
using 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();
cj.LotWafers = new List<WaferInfoRt>();
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)
{
var wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
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();
cj.LotWafers = new List<WaferInfoRt>();
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)
{
var wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(pjSlotWafer.Item2);
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;
var wafers = WaferManager.Instance.GetWaferByProcessJob(pj.Name);
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)
{
var wafer = GetModule(GetWaferReturnedCassette(pj.SlotWafers[i].Item1)).GetWaferInfo(pj.SlotWafers[i].Item2);
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;
var wafers = WaferManager.Instance.GetWaferByProcessJob(pj.Name);
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)
{
var wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(pjSlotWafer.Item2);
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)
{
var bufferWafer = _buffer.GetWaferInfo(i);
// 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;
}
var wafer = _buffer.GetWaferInfo(i);
//分别判断冷却和加热方式温度是否达到
//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;
//第一种情况 : 有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;
}
if (!_waferRobot.IsAvailable && _waferRobot.Target == ModuleName.UnLoad) // 如果WaferRobot正在操作UnLoad
return;
if (!_tmRobot.IsAvailable && _tmRobot.Target == ModuleName.UnLoad) // 如果TMRobot正在操作UnLoad
return;
// 重置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))
{
var 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 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)
&& _pm1.CheckPMToTMRobotTemp())
{
canPickPM1 = true;
}
if (_pm2.IsAvailable && _pm2.HasWafer(0) && _pm2.HasTray(0) && !_pm2.CheckWaferNeedProcess(0)
&& _pm2.CheckPMToTMRobotTemp())
{
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)
{
var wafer = _waferRobot.GetWaferInfo(0);
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;
var 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;
var 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;
}
private bool GetWaferSequenceCoolingTime(ModuleName module, int slot, out int coolingTime)
{
coolingTime = 0;
if (!WaferManager.Instance.CheckHasWafer(module, slot))
return false;
var wafer = WaferManager.Instance.GetWafer(module, slot);
if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
return false;
if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
return false;
if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(module))
return false;
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()
{
var wafer = _buffer.GetWaferInfo(0);
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)
{
var wafer = GetModule(waferModule).GetWaferInfo(waferSlot);
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)
{
var wafer = GetModule(module).GetWaferInfo(slot);
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)
{
var wafer = WaferManager.Instance.GetWafer(module, waferSlot);
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;
}
}
}