| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898 | 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.RecipeCenter;using Aitex.Core.RT.Routine;using Aitex.Core.RT.SCCore;using Aitex.Sorter.Common;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 MECF.Framework.RT.EquipmentLibrary.HardwareUnits.PMs;using System;using System.Collections.Generic;using System.Linq;using System.Xml;using Aitex.Core.Util;using VirgoRT.Modules.Schedulers;using VirgoRT.Scheduler;using VirgoRT.Module;namespace VirgoRT.Modules{    public partial class AutoTransfer : TransferModule, IAutoTransfer    {        private List<ControlJobInfo> _lstControlJobs = new List<ControlJobInfo>();        private List<ProcessJobInfo> _lstProcessJobs = new List<ProcessJobInfo>();        //private Object _locker = new Object();        private List<SchedulerPM> _lstPms = new List<SchedulerPM>();        private List<SchedulerAligner> _lstAligners = new List<SchedulerAligner>();        private List<SchedulerAligner> _lstCoolings = new List<SchedulerAligner>();        private List<SchedulerLoadPort> _lstLps = new List<SchedulerLoadPort>();        private const string LogSource = "Scheduler";        private bool _isCycleMode;        private int _cycleSetPoint = 0;        private int _cycledCount = 0;        private int _cycledWafer = 0;        private bool _isRunningInParallelMode;        private bool _isFixAlignerAndCooling; // 如果不同的尺寸,就固定住4寸和6寸,用不同的aligner,cooling,PM,避免来回        private Dictionary<ModuleName, ModuleName> _mapLpPm = new Dictionary<ModuleName, ModuleName>();        private Dictionary<ModuleName, ModuleName> _mapLpAligner = new Dictionary<ModuleName, ModuleName>();        private Dictionary<ModuleName, ModuleName> _mapLpCooling = new Dictionary<ModuleName, ModuleName>();        private List<ModuleName> _mapTarget = new List<ModuleName>();        public bool HasJobRunning        {            get { return _lstControlJobs.Count > 0; }        }        public bool IsEfemRobotAvavilable => _efemRobot.IsAvailable;        private SchedulerFACallback _faCallback;        private SchedulerDBCallback _dbCallback;        public AutoTransfer()        {            _faCallback = new SchedulerFACallback();            _dbCallback = new SchedulerDBCallback();            if (ModuleHelper.IsInstalled(ModuleName.PMA))                _lstPms.Add(_pma);            if (ModuleHelper.IsInstalled(ModuleName.PMB))                _lstPms.Add(_pmb);            _lstAligners.AddRange(new[] { _aligner1, _aligner2 });            _lstCoolings.AddRange(new[] { _cooling1, _cooling2 });            _lstLps.AddRange(new[] { _lp1, _lp2 });            DATA.Subscribe("Scheduler.CycledCount", () => _cycledCount);            DATA.Subscribe("Scheduler.CycledWafer", () => _cycledWafer);            DATA.Subscribe("Scheduler.CycleSetPoint", () => _cycleSetPoint);            DATA.Subscribe("Scheduler.PjIdList", () => Array.ConvertAll(_lstProcessJobs.ToArray(), x => x.InnerId.ToString()).ToList());            //DATA.Subscribe("LP1.LocalJobName", () =>            //{            //    if (_lstControlJobs.Exists(x => x.Name == "CJ_Local_LP1"))            //        return "CJ_Local_LP1";            //    return "";            //});            //DATA.Subscribe("LP1.LocalJobStatus", () =>            //{            //    var jb = _lstControlJobs.Find(x => x.Name == "CJ_Local_LP1");            //    if (jb != null)            //        return jb.State.ToString();            //    return "";            //});            //DATA.Subscribe("LP2.LocalJobName", () =>            //{            //    if (_lstControlJobs.Exists(x => x.Name == "CJ_Local_LP2"))            //        return "CJ_Local_LP2";            //    return "";            //});            //DATA.Subscribe("LP2.LocalJobStatus", () =>            //{            //    var jb = _lstControlJobs.Find(x => x.Name == "CJ_Local_LP2");            //    if (jb != null)            //        return jb.State.ToString();            //    return "";            //});            foreach (var lp in _lstLps)            {                DATA.Subscribe($"{lp.Module}.LocalJobName", () =>                {                    var cj = _lstControlJobs.FirstOrDefault(x => x.Module == lp.Module.ToString());                    if (cj != null)                        return cj.Name;                    return "";                });                DATA.Subscribe($"{lp.Module}.JobLotName", () =>                {                    var cj = _lstControlJobs.FirstOrDefault(x => x.Module == lp.Module.ToString());                    if (cj != null)                        return cj.LotName;                    return "";                });                DATA.Subscribe($"{lp.Module}.LocalJobStatus", () =>                {                    var cj = _lstControlJobs.FirstOrDefault(x => x.Module == lp.Module.ToString());                    if (cj != null)                        return cj.State.ToString();                    return "";                });                DATA.Subscribe($"{lp.Module}.CurrentRecipeList", () =>                {                    var local = lp;                    List<string> result = Enumerable.Repeat("", 25).ToList();                    for (int i = 0; i < _lstProcessJobs.Count; i++)                    {                        foreach (var wafers in _lstProcessJobs[i].SlotWafers)                        {                            if (wafers.Item1 == local.Module)                            {                                result[wafers.Item2] = _lstProcessJobs[i].Sequence.Name;                            }                        }                    }                    return result;                });            }        }        public void Clear()        {            _efemRobot.ResetTask();            foreach (var pm in _lstPms)            {                pm.ResetTask();            }            foreach (var buffer in _lstAligners)            {                buffer.ResetTask();            }            foreach (var buffer in _lstCoolings)            {                buffer.ResetTask();            }            foreach (var lp in _lstLps)            {                lp.ResetTask();            }            _lstControlJobs.Clear();            _lstProcessJobs.Clear();            _mapLpAligner.Clear();            _mapLpCooling.Clear();            _mapLpPm.Clear();            _isFixAlignerAndCooling = false;            _isRunningInParallelMode = false;            _mapTarget.Clear();        }        #region Job Management        public void CreateJob(Dictionary<string, object> param)        {            _isCycleMode = SC.GetValue<bool>("System.IsCycleMode");            _cycleSetPoint = _isCycleMode ? SC.GetValue<int>("System.CycleCount") : 0;            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 (slotSequence.Length != 25)            {                EV.PostWarningLog(LogSource, $"slot sequence parameter not valid, length is {slotSequence.Length}, should be 25");                _faCallback.JobCreateFailed(module, lotId, jobId, "");                return;            }            if (!ModuleHelper.IsLoadPort(ModuleHelper.Converter(module)))            {                EV.PostWarningLog(LogSource, $"{module} should be LoadPort");                _faCallback.JobCreateFailed(module, lotId, jobId, "");                return;            }            if (string.IsNullOrEmpty(jobId))            {                jobId = "CJ_Local_" + module;            }            if (_lstControlJobs.Exists(x => x.Name == jobId))            {                EV.PostWarningLog(LogSource, $"{jobId} already created");                _faCallback.JobCreateFailed(module, lotId, jobId, "");                return;            }            SchedulerLoadPort lp = GetModule(module) as SchedulerLoadPort;            if (!lp.CheckReadyRunJob())            {                EV.PostWarningLog(LogSource, $"{module} not ready");                _faCallback.JobCreateFailed(module, lotId, jobId, "");                return;            }            ControlJobInfo cj = new ControlJobInfo();            cj.Name = jobId;            cj.Module = module;            cj.LotName = lotId;            cj.LotInnerId = Guid.NewGuid();            cj.LotWafers = new List<WaferInfo>();            cj.CarrierID = lp.GetCarrierID();            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>("Scheduler.GroupWaferBySequence");            for (int i = 0; i < 25; 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))                {                    EV.PostWarningLog(LogSource, $"job wafer: {module} slot {i + 1} not in the carrier");                    //return;                }                if (!WaferManager.Instance.CheckWafer(ModuleHelper.Converter(module), i, WaferStatus.Normal))                {                    EV.PostWarningLog(LogSource, $"job wafer: {module} slot {i + 1} status is {WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).Status}");                    _faCallback.JobCreateFailed(module, lotId, jobId, "");                    return;                }                if (WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).ProcessState != EnumWaferProcessStatus.Idle)                {                    EV.PostWarningLog(LogSource, $"job wafer: {module} slot {i + 1} process status is {WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).ProcessState}");                    _faCallback.JobCreateFailed(module, lotId, jobId, "");                    return;                }                var smallWafer = SC.GetValue<int>($"System.SmallWafer");                //特殊场景,3寸片第一片不能取放                if (i == 0 && (WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).Size == WaferSize.WS3) && (int)smallWafer == 3)                {                    EV.PostWarningLog(LogSource, $"job wafer: {module} 3 inch slot {i + 1} is not supported.");                    _faCallback.JobCreateFailed(module, lotId, jobId, "");                    return;                }                cj.LotWafers.Add(WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i));                WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).SequenceName = slotSequence[i];                WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).NextSequenceStep = 0;                WaferManager.Instance.UpdateWaferLotId(ModuleHelper.Converter(module), i, lotId);                seqSlotWafers[groupName].Add(Tuple.Create(ModuleHelper.Converter(module), i));                cj.JobWaferSize = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).Size;            }            if (seqSlotWafers.Count == 0)            {                EV.PostWarningLog(LogSource, $"job has not assign wafer");                _faCallback.JobCreateFailed(module, lotId, jobId, "");                return;            }            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);                if (!CheckSequencePmReady(pj.Sequence, null, out _, out string reason))                {                    EV.PostWarningLog(LogSource, $"no valid chamber for the {reason}");                    _faCallback.JobCreateFailed(module, lotId, jobId, "");                    return;                }                if (!CheckSequenceOrderOk(pj.Sequence, out reason))                {                    EV.PostWarningLog(LogSource, $"sequence path not valid, {reason}");                    _faCallback.JobCreateFailed(module, lotId, jobId, "");                    return;                }                if (!SC.GetValue<bool>("System.IsATMMode") && !CheckSequenceRecipeFileValid(pj.Sequence, out reason))                {                    EV.PostWarningLog(LogSource, $"recipe file not valid in the sequence, {reason}");                    _faCallback.JobCreateFailed(module, lotId, jobId, "");                    return;                }                if (!SetSequenceTemperatureInfo(pj.Sequence, out reason))                {                    EV.PostWarningLog(LogSource, $"sequence recipe temperature not valid, {reason}");                    _faCallback.JobCreateFailed(module, lotId, jobId, "");                    return;                }                pjs.Add(pj);            }            _dbCallback.LotUpdate(cj);            foreach (var pj in pjs)            {                cj.ProcessJobNameList.Add(pj.Name);                _lstProcessJobs.Add(pj);            }            _lstControlJobs.Add(cj);            UpdateParallelMode();            _faCallback.JobCreated(cj, GetFirstProcessJob(cj));        }        public ProcessJobInfo GetFirstProcessJob(ControlJobInfo cj)        {            foreach (var pj in _lstProcessJobs)            {                if (pj.ControlJobName == cj.Name)                    return pj;            }            return null;        }        public 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 pj in _lstProcessJobs)            {                if (pj.ControlJobName == cj.Name)                {                    pj.SetState(EnumProcessJobState.Stopping);                }            }            _faCallback.JobStopped(cj, GetFirstProcessJob(cj));            _dbCallback.LotFinished(cj);        }        public 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;            }            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;                    WaferInfo[] wafers = WaferManager.Instance.GetWaferByProcessJob(pj.Name);                    foreach (var waferInfo in wafers)                    {                        waferInfo.ProcessJob = null;                        waferInfo.NextSequenceStep = 0;                        if (waferInfo.ProcessState != EnumWaferProcessStatus.Completed)                            unprocessed++;                    }                    JobDataRecorder.EndPJ(pj.InnerId.ToString(), aborted, unprocessed);                }            }            _faCallback.JobAborted(cj, GetFirstProcessJob(cj));            _dbCallback.LotFinished(cj);            foreach (var pj in pjAbortList)            {                _lstProcessJobs.Remove(pj);            }            _lstControlJobs.Remove(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;            }            if (cj.State == EnumControlJobState.Paused)            {                cj.SetState(EnumControlJobState.Executing);            }            _faCallback.JobResumed(cj, GetFirstProcessJob(cj));        }        public void StartJob(string jobName)        {            ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);            if (cj == null)            {                EV.PostWarningLog(LogSource, $"start job rejected, not found job with id {jobName}");                return;            }            if (cj.State == EnumControlJobState.WaitingForStart)            {                cj.SetState(EnumControlJobState.Executing);                //PreJobClean(cj);                (GetModule(cj.Module) as SchedulerLoadPort).NoteJobStart();                cj.StartTime = DateTime.Now;                _dbCallback.LotCreated(cj);                _faCallback.JobStarted(cj, GetFirstProcessJob(cj));            }        }        public 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;            }            if (cj.State == EnumControlJobState.Executing)            {                cj.SetState(EnumControlJobState.Paused);            }            _faCallback.JobPaused(cj, GetFirstProcessJob(cj));        }        public void Map(string moduleName)        {            ModuleName target = ModuleHelper.Converter(moduleName);            if (!ModuleHelper.IsLoadPort(target))            {                EV.PostWarningLog(LogSource, $"Invalid map target {target}");                return;            }            if (!_mapTarget.Contains(target))            {                _mapTarget.Add(target);            }        }        #endregion Job Management        public Result Start(params object[] objs)        {            _isCycleMode = SC.GetValue<bool>("System.IsCycleMode");            _cycleSetPoint = _isCycleMode ? SC.GetValue<int>("System.CycleCount") : 0;            _cycledWafer = 0;            _cycledCount = 0;            bool hasPmOnline = false;            foreach (var schedulerPm in _lstPms)            {                if (schedulerPm.IsAvailable)                {                    schedulerPm.SetPMAuto();                    hasPmOnline = true;                    continue;                }            }            if (!hasPmOnline)            {                EV.PostWarningLog("Scheduler", "can not change to auto mode, at least one process chamber be online");                return Result.FAIL;            }            return Result.RUN;        }        public Result Monitor()        {            MonitorEfemRobotMapTask();            ControlJobInfo cjActive = _lstControlJobs.Find(x => x.State == EnumControlJobState.Executing);            if (cjActive != null)            {                MonitorModuleTasks();            }            MonitorJobTasks();            MonitorCleanTasks();            return Result.RUN;        }        #region Job task        public Result MonitorJobTasks()        {            UpdateParallelMode();            UpdateProcessJobStatus();            UpdateControlJobStatus();            StartNewJob();            return Result.RUN;        }        private void UpdateParallelMode()        {            bool enableParallel = SC.GetValue<bool>("Scheduler.IsRunInParallelMode");            bool bothLpHasJob = true;            _isRunningInParallelMode = enableParallel;            Dictionary<ModuleName, Dictionary<ModuleName, float>> lpNeededPmTemperature = new Dictionary<ModuleName, Dictionary<ModuleName, float>>();            foreach (var lp in _lstLps)            {                var cj = _lstControlJobs.Find(x => x.Module == lp.Module.ToString());                bothLpHasJob = bothLpHasJob && (cj != null);                if (cj != null)                {                    lpNeededPmTemperature[lp.Module] = new Dictionary<ModuleName, float>();                    var pj = _lstProcessJobs.FirstOrDefault(x => x.ControlJobName == cj.Name);                    if (pj != null)                    {                        var seq = pj.Sequence;                        for (int i = 0; i < seq.Steps.Count; i++)                        {                            SequenceStepInfo stepInfo = seq.Steps[i];                            foreach (var module in stepInfo.StepModules)                            {                                if (ModuleHelper.IsPm(module) && !lpNeededPmTemperature[lp.Module].ContainsKey(module))                                {                                    lpNeededPmTemperature[lp.Module][module] = (float)seq.Steps[i]                                        .StepParameter[module == ModuleName.PMA ? "PMATemp" : "PMBTemp"];                                }                            }                        }                    }                }            }            bool needSamePm = false;            ModuleName pmSource = ModuleName.System;            foreach (var pmNeeded in lpNeededPmTemperature)            {                if (pmNeeded.Value.Count == 1)                {                    var source = pmNeeded.Value.Keys.First();                    if (source != pmSource)                    {                        pmSource = source;                    }                    else                    {                        needSamePm = true;                        break;                    }                }                else if(pmNeeded.Value.Count > 1)                {                    needSamePm = true;                }            }            var needFixPosition = enableParallel && bothLpHasJob && !needSamePm;            _isRunningInParallelMode = needFixPosition;            if (needFixPosition != _isFixAlignerAndCooling)            {                _isFixAlignerAndCooling = needFixPosition;                if (needFixPosition)                {                    //aligner固定不做逻辑                    _mapLpAligner[ModuleName.LP1] = ModuleName.Aligner1;                    _mapLpAligner[ModuleName.LP2] = ModuleName.Aligner2;                    _mapLpCooling[ModuleName.LP1] = ModuleName.Cooling1;                    _mapLpCooling[ModuleName.LP2] = ModuleName.Cooling2;                    bool assigned = false;                    foreach (var pmNeeded in lpNeededPmTemperature)                    {                        if (pmNeeded.Value.Count == 1)                        {                            _mapLpPm[pmNeeded.Key] = pmNeeded.Value.Keys.First();                            var anotherLp = pmNeeded.Key == ModuleName.LP1 ? ModuleName.LP2 : ModuleName.LP1;                            var anotherPm = _mapLpPm[pmNeeded.Key] == ModuleName.PMA ? ModuleName.PMB : ModuleName.PMA;                            _mapLpPm[anotherLp] = anotherPm;                            assigned = true;                            break;                        }                    }                    if (!assigned)                    {                        _mapLpPm[ModuleName.LP1] = ModuleName.PMA;                        _mapLpPm[ModuleName.LP2] = ModuleName.PMB;                        float pmaTemp = ((SchedulerPM)GetModule(ModuleName.PMA.ToString())).Temperature;                        float pmbTemp = ((SchedulerPM)GetModule(ModuleName.PMB.ToString())).Temperature;                        float tempCurrent = Math.Abs(lpNeededPmTemperature[ModuleName.LP1][ModuleName.PMA] - pmaTemp)                            + Math.Abs(lpNeededPmTemperature[ModuleName.LP2][ModuleName.PMB] - pmbTemp);                        float tempAnother = Math.Abs(lpNeededPmTemperature[ModuleName.LP1][ModuleName.PMB] - pmbTemp)                                            + Math.Abs(lpNeededPmTemperature[ModuleName.LP2][ModuleName.PMA] - pmaTemp);                        if (tempAnother < tempCurrent)                        {                            _mapLpPm[ModuleName.LP1] = ModuleName.PMB;                            _mapLpPm[ModuleName.LP2] = ModuleName.PMA;                        }                    }                }            }        }        private void UpdateProcessJobStatus()        {            foreach (var pj in _lstProcessJobs)            {                if (pj.State == EnumProcessJobState.Processing)                {                    if (CheckAllWaferReturned(pj, true))                    {                        pj.SetState(EnumProcessJobState.ProcessingComplete);                        JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0);                    }                }                else if (pj.State == EnumProcessJobState.Stopping)                {                    if (CheckAllWaferReturned(pj, false))                    {                        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 (!GetModule(cj.Module).IsAvailable)                {                    allControlJobComplete = false;                    continue;                }                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);                        cj.EndTime = DateTime.Now;                        if( !(_isCycleMode && _cycledCount+1 < _cycleSetPoint))                        {                            CompleteJobClean(cj);                        }                        _faCallback.JobFinished(cj, GetFirstProcessJob(cj));                        _dbCallback.LotFinished(cj);                        if (!(_isCycleMode && _cycledCount < _cycleSetPoint))                            (GetModule(cj.Module) as SchedulerLoadPort).NoteJobComplete();                    }                }                LoadportCassetteState state = (LoadportCassetteState)DATA.Poll($"{cj.Module}.CassetteState");                if (cj.State == EnumControlJobState.Completed && state != LoadportCassetteState.Normal)                {                    cjRemoveList.Add(cj);                }                allControlJobComplete = allControlJobComplete && cj.State == EnumControlJobState.Completed;            }            if (_isCycleMode && _cycledCount < (_isCycleMode ? _cycleSetPoint : 0))            {                int countPerCycle = 0;                int countProcessed = 0;                foreach (var pj in _lstProcessJobs)                {                    foreach (var pjSlotWafer in pj.SlotWafers)                    {                        countPerCycle++;                        WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);                        if (!wafer.IsEmpty && !CheckWaferNeedProcess(pjSlotWafer.Item1, pjSlotWafer.Item2))                            countProcessed++;                    }                }                _cycledWafer = _cycledCount * countPerCycle + countProcessed;                if (allControlJobComplete)                {                    _cycledCount++;                    if (_cycledCount < _cycleSetPoint)                    {                        foreach (var cj in _lstControlJobs)                        {                            cj.SetState(EnumControlJobState.Executing);                            //循环模式,不做PreJob Clean                            //PreJobClean(cj);                            cj.LotInnerId = Guid.NewGuid();                            //PreJobClean(cj);                            _dbCallback.LotCreated(cj);                        }                        foreach (var pj in _lstProcessJobs)                        {                            pj.SetState(EnumProcessJobState.Queued);                            pj.InnerId = Guid.NewGuid();                            foreach (var pjSlotWafer in pj.SlotWafers)                            {                                WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, 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);            }            if (cjRemoveList.Count > 0)            {                UpdateParallelMode();            }        }        public bool CheckJobJustDone(out string sJobName)        {            foreach (var cj in _lstControlJobs)            {                if (cj.State == EnumControlJobState.Completed && !cj.BeenPosted)                {                    //LP;WaferSize;Lot;Number;Start;End;                    sJobName = $"{cj.Module};{cj.JobWaferSize};{cj.LotName};{cj.LotWafers.Count};{cj.StartTime:T};{cj.EndTime:T}";                    cj.BeenPosted = true;                    return true;                }            }            //string strInfo = $"{cj.Module} has finished: \r\n\r\nProcessed wafer number: {cj.LotWafers.Count} \r\nStart time: {cj.BeginTime} \r\nEnd time: {cj.EndTime} \r\nDuration: {(cj.EndTime - cj.BeginTime).TotalSeconds:F0} sec";            sJobName = "NULL";            return false;        }        public bool CheckAllJobDone()        {            foreach (var cj in _lstControlJobs)            {                if (cj.State == EnumControlJobState.Executing || cj.State == EnumControlJobState.Paused)                    return false;            }            return true;        }        protected void StartNewJob()        {            ControlJobInfo cjActived = null;            List<ModuleName> pmOccupied = GetPmUsedInRunningPj();            foreach (var cj in _lstControlJobs)            {                if (cj.State != EnumControlJobState.Executing)                    continue;                cjActived = cj;                foreach (var pjName in cjActived.ProcessJobNameList)                {                    var pj = _lstProcessJobs.Find(x => x.Name == pjName);                    if (pj == null)                    {                        LOG.Error($"Not find pj named {pjName} in {cjActived.Name}");                        continue;                    }                    if (pj.State == EnumProcessJobState.Queued)                    {                        if (CheckSequencePmReady(pj.Sequence, pmOccupied, out var pmUsed, out string reason))                        {                            ActiveProcessJob(pj);                            foreach (var moduleName in pmUsed)                            {                                if (!pmOccupied.Contains(moduleName))                                    pmOccupied.Add(moduleName);                            }                        }                        break;                    }                }                if (!_isRunningInParallelMode)                    break;            }        }        private bool ActiveProcessJob(ProcessJobInfo pj)        {            foreach (var pjSlotWafer in pj.SlotWafers)            {                WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, 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(), carrier.InnerId.ToString(), cj.InnerId.ToString(), pj.Name, cj.Module, cj.Module, pj.SlotWafers.Count);            pj.SetState(EnumProcessJobState.Processing);            PreJobClean(cj);            return true;        }        #endregion Job task        #region Module task        public Result MonitorModuleTasks()        {            MonitorPMTask();            MonitorEfemRobotTask();            MonitorAlignerTask();            MonitorCoolingTask();            MonitorInterlockTask();            return Result.RUN;        }        private void MonitorInterlockTask()        {            foreach (var cj in _lstControlJobs)            {                if (cj.State == EnumControlJobState.Executing || cj.State == EnumControlJobState.Paused ||                    cj.State == EnumControlJobState.WaitingForStart)                {                    var lp = GetModule(cj.Module);                    if (!(lp as SchedulerLoadPort).CheckPlaced())                    {                        EV.PostAlarmLog("System", "Cassette removed while job not finished.");                        Singleton<RouteManager>.Instance.PostMsg(RouteManager.MSG.ERROR);                    }                }            }        }        private void MonitorAlignerTask()        {            foreach (var schedulerBuffer in _lstAligners)            {                if (!schedulerBuffer.IsAvailable                    || WaferManager.Instance.CheckNoWafer(schedulerBuffer.Module, 0)                    )                    continue;                if (CheckWaferNextStepIsAlign(schedulerBuffer.Module, 0))                {                    WaferInfo wafer = WaferManager.Instance.GetWafers(schedulerBuffer.Module)[0];                    var job = wafer.ProcessJob;                    GetWaferSequenceAlignTime(schedulerBuffer.Module, 0, out float time);                    if (schedulerBuffer.Align(time))                    {                        wafer.NextSequenceStep++;                    }                }            }        }        private void MonitorCoolingTask()        {            foreach (var schedulerBuffer in _lstCoolings)            {                if (!schedulerBuffer.IsAvailable                    || WaferManager.Instance.CheckNoWafer(schedulerBuffer.Module, 0)                )                    continue;                if (CheckWaferNextStepIsCooling(schedulerBuffer.Module, 0))                {                    WaferInfo wafer = WaferManager.Instance.GetWafers(schedulerBuffer.Module)[0];                    var job = wafer.ProcessJob;                    GetWaferSequenceAlignTime(schedulerBuffer.Module, 0, out float time);                    if (schedulerBuffer.Align(time))                    {                        wafer.NextSequenceStep++;                    }                }            }        }        private void MonitorEfemRobotTask()        {            if (!_efemRobot.IsAvailable)                return;            //efem robot is idle, release all the target             foreach (var pm in _lstPms)            {                if (pm.IsWaitTransfer(ModuleName.EfemRobot))                {                    pm.PostTransfer(ModuleName.EfemRobot);                }            }            foreach (var buffer in _lstCoolings)            {                if (buffer.IsWaitTransfer(ModuleName.EfemRobot))                {                    buffer.PostTransfer(ModuleName.EfemRobot);                }            }            foreach (var buffer in _lstAligners)            {                if (buffer.IsWaitTransfer(ModuleName.EfemRobot))                {                    buffer.PostTransfer(ModuleName.EfemRobot);                }            }            foreach (var lp in _lstLps)            {                if (lp.IsWaitTransfer(ModuleName.EfemRobot, EnumTransferType.Pick))                {                    lp.PostTransfer(ModuleName.EfemRobot);                }                if (lp.IsWaitTransfer(ModuleName.EfemRobot, EnumTransferType.Place))                {                    lp.PostTransfer(ModuleName.EfemRobot);                    ProcessJobInfo pj = WaferManager.Instance.GetWafer(lp.Module, lp.InTransferSlot)                        .ProcessJob;                    ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == pj.ControlJobName);                    _faCallback.JobWaferEnd(cj, pj, lp.Module.ToString(), lp.InTransferSlot);                }            }            bool blade0HasWaferAndNeedCooling = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 0) &&                                                CheckWaferNeedCooling(ModuleName.EfemRobot, 0);            bool blade1HasWaferAndNeedCooling = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 1) &&                                                CheckWaferNeedCooling(ModuleName.EfemRobot, 1);            if (blade0HasWaferAndNeedCooling || blade1HasWaferAndNeedCooling)            {                MonitorEfemRobotCoolingTask();                if (!_efemRobot.IsAvailable)                    return;            }            bool blade0HasWaferAndComplete = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 0)                                             && !CheckWaferNeedProcess(ModuleName.EfemRobot, 0)                                             && !CheckWaferNeedCooling(ModuleName.EfemRobot, 0);            bool blade1HasWaferAndComplete = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 1)                                              && !CheckWaferNeedProcess(ModuleName.EfemRobot, 1)                                              && !CheckWaferNeedCooling(ModuleName.EfemRobot, 1);            if (blade0HasWaferAndComplete || blade1HasWaferAndComplete || ModuleHelper.IsLoadPort(_efemRobot.PreviousTarget))            {                MonitorEfemRobotLoadPortTask();                if (!_efemRobot.IsAvailable)                    return;            }            //bool blade0HasWaferAndNeedAligner = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 0) &&            //                                    CheckWaferNeedAlign(ModuleName.EfemRobot, 0);            //bool blade1HasWaferAndNeedAligner = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 1) &&            //                                    CheckWaferNeedAlign(ModuleName.EfemRobot, 1);            //if (blade0HasWaferAndNeedAligner || blade1HasWaferAndNeedAligner)            //{            //    MonitorEfemRobotAlignerTask();            //    if (!_efemRobot.IsAvailable)            //        return;            //}            MonitorEfemRobotAlignerTask();            if (!_efemRobot.IsAvailable)                return;            MonitorEfemRobotPMTask();            if (!_efemRobot.IsAvailable)                return;            MonitorEfemRobotLoadPortTask();            if (!_efemRobot.IsAvailable)                return;            MonitorEfemRobotCoolingTask();            if (!_efemRobot.IsAvailable)                return;            MonitorEfemRobotGotoTask();            if (!_efemRobot.IsAvailable)                return;        }        private void MonitorEfemRobotMapTask()        {            if (!_efemRobot.IsAvailable)                return;            if (_mapTarget.Count > 0)            {                ModuleName first = _mapTarget[0];                //避免重复map,job信息被清除                foreach (var cj in _lstControlJobs)                {                    if (cj.Module != first.ToString())                        continue;                    if (cj.State == EnumControlJobState.Executing || cj.State == EnumControlJobState.Paused)                    {                        EV.PostWarningLog("System", $"{first} is running, can not map again");                        _mapTarget.Remove(first);                    }                }                SchedulerLoadPort lp = GetModule(first.ToString()) as SchedulerLoadPort;                if (lp != null && lp.IsAvailable)                {                    _efemRobot.Map(first);                    _mapTarget.Remove(first);                }            }        }        private void MonitorEfemRobotPMTask()        {            if (!_efemRobot.IsAvailable)                return;            //swap PM            if (WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 0) ^ WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 1))            {                Hand pickBlade = WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 0) ? Hand.Blade1 : Hand.Blade2;                Hand placeBlade = pickBlade == Hand.Blade1 ? Hand.Blade2 : Hand.Blade1;                SchedulerPM swapPm = null;                foreach (var pm in _lstPms)                {                    if (!pm.IsAvailable || !WaferManager.Instance.CheckHasWafer(pm.Module, 0)                                        || CheckWaferNeedProcess(pm.Module, 0, pm.Module)                                        || !pm.IsReadyForPick(ModuleName.EfemRobot, 0, pickBlade)                                        || !CheckVacuumWaferHasAvailableTarget(pm.Module, 0)                                        || !CheckWaferNextProcessIn(ModuleName.EfemRobot, (int)placeBlade, pm.Module))                        continue;                    if (swapPm == null || (pm.WaferArriveTicks[0] < swapPm.WaferArriveTicks[0]))                    {                        swapPm = pm;                    }                }                if (swapPm != null)                {                    if (_efemRobot.PickAndPlace(swapPm.Module, 0, 0, pickBlade, placeBlade))                    {                        swapPm.WaitTransfer(ModuleName.EfemRobot, EnumTransferType.Pick, 0);                        return;                    }                }            }            //place to pm            bool blade0HasWaferAndNeedProcess = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 0)                                                && CheckWaferNeedProcess(ModuleName.EfemRobot, 0);            bool blade1HasWaferAndNeedProcess = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 1)                                                && CheckWaferNeedProcess(ModuleName.EfemRobot, 1);            if (blade0HasWaferAndNeedProcess || blade1HasWaferAndNeedProcess)            {                List<Hand> orderedBlade = new List<Hand>();                if (blade0HasWaferAndNeedProcess && blade1HasWaferAndNeedProcess)                {                    int result = CompareWaferPriority(ModuleName.EfemRobot, 0, ModuleName.EfemRobot, 1);                    if (result < 0 || (result==0 && _efemRobot.WaferArriveTicks[1] < _efemRobot.WaferArriveTicks[0]))                    {                        orderedBlade.AddRange(new List<Hand>() {Hand.Blade2, Hand.Blade1});                    }                    else                    {                        orderedBlade.AddRange(new List<Hand>() { Hand.Blade1, Hand.Blade2 });                    }                }                else                {                    orderedBlade.Add(blade0HasWaferAndNeedProcess ? Hand.Blade1 : Hand.Blade2);                }                foreach (Hand placeBlade in orderedBlade)                {                    foreach (var pm in _lstPms)                    {                        if (!pm.IsAvailable                            || !WaferManager.Instance.CheckNoWafer(pm.Module, 0)                            || !CheckWaferNextProcessIn(ModuleName.EfemRobot, (int)placeBlade, pm.Module))                            continue;                        if (_isFixAlignerAndCooling && GetWaferCountOutofLP(ModuleName.LP1) <= 1 && GetWaferCountOutofLP(ModuleName.LP2) <= 1)                        {                            int origin = WaferManager.Instance.GetWafer(ModuleName.EfemRobot, (int)placeBlade).OriginStation;                            if (origin == (int)ModuleName.LP1 && _mapLpPm[ModuleName.LP1] != pm.Module)                                continue;                            if (origin == (int)ModuleName.LP2 && _mapLpPm[ModuleName.LP2] != pm.Module)                                continue;                        }                        if (!pm.IsReadyForPlace(ModuleName.EfemRobot, 0, placeBlade))                            continue;                        if (_efemRobot.Place(pm.Module, 0, placeBlade))                        {                            pm.WaitTransfer(ModuleName.EfemRobot, EnumTransferType.Place, 0);                            return;                        }                    }                }            }            if (!_efemRobot.IsAvailable)                return;            //pick from pm            bool blade1Empty = WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 0);            bool blade2Empty = WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 1);            if (blade1Empty || blade2Empty)            {                ModuleName pickPm = ModuleName.System;                int preOriginSlot = int.MaxValue;                string pmPj = string.Empty;                int preWaferCountInCooling = 0;                foreach (var schedulerPm in _lstPms)                {                    if (!schedulerPm.IsAvailable                        || WaferManager.Instance.CheckNoWafer(schedulerPm.Module, 0)                        || CheckWaferNeedProcess(schedulerPm.Module, 0, schedulerPm.Module))                        continue;                    WaferInfo wafer = WaferManager.Instance.GetWafer(schedulerPm.Module, 0);                    bool pickAllowed = CheckVacuumWaferHasAvailableTarget(schedulerPm.Module, 0);                    if (!pickAllowed)                        continue;                    if ((pickPm == ModuleName.System)                        || (wafer.OriginSlot < preOriginSlot && pmPj == wafer.ProcessJob.Name)                        || (GetCoolingWaferCount(wafer.ProcessJob.Name) < preWaferCountInCooling))                    {                        preOriginSlot = wafer.OriginSlot;                        pickPm = schedulerPm.Module;                        pmPj = wafer.ProcessJob.Name;                        preWaferCountInCooling = GetCoolingWaferCount(pmPj);                        continue;                    }                }                if (pickPm != ModuleName.System)                {                    Hand pickBlade = blade1Empty ? Hand.Blade1 : Hand.Blade2;                    if (blade1Empty && blade2Empty)                    {                        if (_efemRobot.WaferArriveTicks[1] < _efemRobot.WaferArriveTicks[0])                            pickBlade = Hand.Blade2;                    }                    SchedulerModule pm = GetModule(pickPm.ToString());                    if (pm.IsReadyForPick(ModuleName.EfemRobot, 0, pickBlade))                    {                        if (_efemRobot.Pick(pm.Module, 0, pickBlade))                        {                            pm.WaitTransfer(ModuleName.EfemRobot, EnumTransferType.Pick, 0);                            return;                        }                    }                }            }        }        private void MonitorEfemRobotLoadPortTask()        {            if (!_efemRobot.IsAvailable)                return;            //pick            int maxOutWafer = 6;//cooling*2 + Aligner*2+PM*2            bool blade1Empty = WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 0);            bool blade2Empty = WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 1);            bool bothAlignerEmpty = true;            foreach (var schedulerAligner in _lstAligners)            {                if (WaferManager.Instance.CheckHasWafer(schedulerAligner.Module, 0))                {                    bothAlignerEmpty = false;                    break;                }            }            bool bothBladeEmpty = blade1Empty && blade2Empty;            if (GetWaferCountOutofLP(ModuleName.System) < maxOutWafer                && GetWaferCountInJobQueue(ModuleName.System) > 0                && (bothBladeEmpty || (bothAlignerEmpty && (blade1Empty || blade2Empty))))            {                SlotItem position = GetNextWaferInJobQueue(ModuleName.System);                if (position != null                    && CheckWaferHasAvailableTarget(position.Module, position.Slot)                    && CheckWaferPmTemperatureIsOk(position.Module, position.Slot))                {                    SchedulerLoadPort lp = (SchedulerLoadPort)GetModule(position.Module.ToString());                    Hand pickBlade = blade1Empty ? Hand.Blade1 : Hand.Blade2;                    if (lp.IsReadyForPick(ModuleName.EfemRobot, position.Slot, pickBlade))                    {                        if (_efemRobot.Pick(position.Module, position.Slot, pickBlade))                        {                            lp.WaitTransfer(ModuleName.EfemRobot, EnumTransferType.Pick, position.Slot);                            ProcessJobInfo pj = WaferManager.Instance.GetWafer(position.Module, position.Slot)                                .ProcessJob;                            ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == pj.ControlJobName);                            _faCallback.JobWaferStart(cj, pj, position.Module.ToString(), position.Slot);                            return;                        }                    }                }            }            if (!_efemRobot.IsAvailable)                return;            //place            bool blade0HasWaferAndProcessed = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 0)                                              && !CheckWaferNeedProcess(ModuleName.EfemRobot, 0)                                              && !CheckWaferNeedCooling(ModuleName.EfemRobot, 0);            bool blade1HasWaferAndProcessed = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 1)                                              && !CheckWaferNeedProcess(ModuleName.EfemRobot, 1)                                              && !CheckWaferNeedCooling(ModuleName.EfemRobot, 1);            if (blade0HasWaferAndProcessed || blade1HasWaferAndProcessed)            {                Hand placeBlade = blade0HasWaferAndProcessed ? Hand.Blade1 : Hand.Blade2;                if (blade0HasWaferAndProcessed && blade1HasWaferAndProcessed)                {                    if (WaferManager.Instance.GetWafer(ModuleName.EfemRobot, 1).OriginSlot <                        WaferManager.Instance.GetWafer(ModuleName.EfemRobot, 0).OriginSlot)                    {                        placeBlade = Hand.Blade2;                    }                }                SlotItem destination = GetWaferReturnLoadPort(_efemRobot.Module, (int)placeBlade);                if (destination != null && ModuleHelper.IsLoadPort(destination.Module))                {                    SchedulerLoadPort lp = (SchedulerLoadPort)GetModule(destination.Module.ToString());                    if (lp.IsReadyForPlace(ModuleName.EfemRobot, destination.Slot, placeBlade))                    {                        if (_efemRobot.Place(destination.Module, destination.Slot, (Hand)placeBlade))                        {                            lp.WaitTransfer(ModuleName.EfemRobot, EnumTransferType.Place, destination.Slot);                            //_cycledTotalWafer++;                            //if (SC.ContainsItem("System.TotalCycledWafer"))                            //    SC.SetItemValue("System.TotalCycledWafer", _cycledTotalWafer);                            return;                        }                    }                }            }        }        private void MonitorEfemRobotAlignerTask()        {            if (!_efemRobot.IsAvailable)                return;            //swap Aligner            if (WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 0) ^ WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 1))            {                Hand pickBlade = WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 0) ? Hand.Blade1 : Hand.Blade2;                Hand placeBlade = pickBlade == Hand.Blade1 ? Hand.Blade2 : Hand.Blade1;                SchedulerAligner swapAligner = null;                foreach (var aligner in _lstAligners)                {                    if (!aligner.IsAvailable || !WaferManager.Instance.CheckHasWafer(aligner.Module, 0)                                             || !aligner.IsReadyForPick(ModuleName.EfemRobot, 0, pickBlade)                                             || CheckWaferNeedAlign(aligner.Module, 0)                                             || !CheckWaferNeedAlign(ModuleName.EfemRobot, (int)placeBlade))                        continue;                    if (swapAligner == null || (aligner.WaferArriveTicks[0] < swapAligner.WaferArriveTicks[0]))                    {                        swapAligner = aligner;                    }                }                if (swapAligner != null)                {                    if (_efemRobot.PickAndPlace(swapAligner.Module, 0, 0, pickBlade, placeBlade))                    {                        swapAligner.WaitTransfer(ModuleName.EfemRobot, EnumTransferType.Pick, 0);                        return;                    }                }            }            //place to aligner            bool blade0HasWaferAndNeedAligner = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 0) &&                                                CheckWaferNeedAlign(ModuleName.EfemRobot, 0);            bool blade1HasWaferAndNeedAligner = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 1) &&                                                CheckWaferNeedAlign(ModuleName.EfemRobot, 1);            if (blade0HasWaferAndNeedAligner || blade1HasWaferAndNeedAligner)            {                foreach (var buffer in _lstAligners)                {                    if (!buffer.IsAvailable || !WaferManager.Instance.CheckNoWafer(buffer.Module, 0))                        continue;                    List<Hand> orderedBlade = new List<Hand>();                    if (blade0HasWaferAndNeedAligner && blade1HasWaferAndNeedAligner)                    {                        int result = CompareWaferPriority(ModuleName.EfemRobot, 0, ModuleName.EfemRobot, 1);                        if (result < 0 || (result == 0 && _efemRobot.WaferArriveTicks[1] < _efemRobot.WaferArriveTicks[0]))                        {                            orderedBlade.AddRange(new List<Hand>() { Hand.Blade2, Hand.Blade1 });                        }                        else                        {                            orderedBlade.AddRange(new List<Hand>() { Hand.Blade1, Hand.Blade2 });                        }                    }                    else                    {                        orderedBlade.Add(blade0HasWaferAndNeedAligner ? Hand.Blade1 : Hand.Blade2);                    }                    foreach (Hand placeBlade in orderedBlade)                    {                        if (_isFixAlignerAndCooling && GetWaferCountOutofLP(ModuleName.LP1) <= 1 && GetWaferCountOutofLP(ModuleName.LP2) <= 1)                        {                            int origin = WaferManager.Instance.GetWafer(ModuleName.EfemRobot, (int)placeBlade).OriginStation;                            if (origin == (int)ModuleName.LP1 && _mapLpAligner[ModuleName.LP1] != buffer.Module)                                continue;                            if (origin == (int)ModuleName.LP2 && _mapLpAligner[ModuleName.LP2] != buffer.Module)                                continue;                        }                        if (!buffer.IsReadyForPlace(ModuleName.EfemRobot, 0, placeBlade))                            continue;                        if (_efemRobot.Place(buffer.Module, 0, placeBlade))                        {                            buffer.WaitTransfer(ModuleName.EfemRobot, EnumTransferType.Place, 0);                            return;                        }                    }                }            }            if (!_efemRobot.IsAvailable)                return;            //pick from aligner            bool blade1Empty = WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 0);            bool blade2Empty = WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 1);            if (blade1Empty || blade2Empty)            {                ModuleName pickAligner = ModuleName.System;                int preOriginSlot = int.MaxValue;                string prePj = string.Empty;                int preWaferCountInCooling = 0;                foreach (var schedulerAligner in _lstAligners)                {                    if (!schedulerAligner.IsAvailable                        || WaferManager.Instance.CheckNoWafer(schedulerAligner.Module, 0)                        || CheckWaferNeedAlign(schedulerAligner.Module, 0))                        continue;                    WaferInfo wafer = WaferManager.Instance.GetWafer(schedulerAligner.Module, 0);                    bool pickAllowed = CheckBufferWaferHasAvailableTarget(schedulerAligner.Module, 0)                        || (blade1Empty && blade2Empty);                    if (!pickAllowed)                    {                        continue;                    }                    if ((pickAligner == ModuleName.System)                        || (wafer.OriginSlot < preOriginSlot && prePj == wafer.ProcessJob.Name)                        || (GetCoolingWaferCount(wafer.ProcessJob.Name) < preWaferCountInCooling))                    {                        preOriginSlot = wafer.OriginSlot;                        pickAligner = schedulerAligner.Module;                        prePj = wafer.ProcessJob.Name;                        preWaferCountInCooling = GetCoolingWaferCount(prePj);                        continue;                    }                }                if (pickAligner != ModuleName.System)                {                    SchedulerModule buffer = GetModule(pickAligner.ToString());                    Hand pickBlade = blade1Empty ? Hand.Blade1 : Hand.Blade2;                    if (!CheckWaferNeedProcess(ModuleName.EfemRobot, 0) &&                        !CheckWaferNeedProcess(ModuleName.EfemRobot, 1))                    {                        if (buffer.IsReadyForPick(ModuleName.EfemRobot, 0, pickBlade))                        {                            if (_efemRobot.Pick(buffer.Module, 0, pickBlade))                            {                                buffer.WaitTransfer(ModuleName.EfemRobot, EnumTransferType.Pick, 0);                                return;                            }                        }                    }                }            }        }        private void MonitorEfemRobotCoolingTask()        {            if (!_efemRobot.IsAvailable)                return;            //swap Cooling            if (WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 0) ^ WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 1))            {                Hand pickBlade = WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 0) ? Hand.Blade1 : Hand.Blade2;                Hand placeBlade = pickBlade == Hand.Blade1 ? Hand.Blade2 : Hand.Blade1;                SchedulerAligner swapCooling = null;                foreach (var cooling in _lstCoolings)                {                    if (!cooling.IsAvailable || !WaferManager.Instance.CheckHasWafer(cooling.Module, 0)                                             || !cooling.IsReadyForPick(ModuleName.EfemRobot, 0, pickBlade)                                             || !CheckWaferNeedCooling(ModuleName.EfemRobot, (int)placeBlade))                        continue;                    if (swapCooling == null || (cooling.WaferArriveTicks[0] < swapCooling.WaferArriveTicks[0]))                    {                        swapCooling = cooling;                    }                }                if (swapCooling != null)                {                    if (_efemRobot.PickAndPlace(swapCooling.Module, 0, 0, pickBlade, placeBlade))                    {                        swapCooling.WaitTransfer(ModuleName.EfemRobot, EnumTransferType.Pick, 0);                        return;                    }                }            }            if (!_efemRobot.IsAvailable)                return;            //place to cooling            bool blade0HasWaferAndNeedCooling = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 0) &&                                                CheckWaferNeedCooling(ModuleName.EfemRobot, 0);            bool blade1HasWaferAndNeedCooling = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 1) &&                                                CheckWaferNeedCooling(ModuleName.EfemRobot, 1);            if (blade0HasWaferAndNeedCooling || blade1HasWaferAndNeedCooling)            {                foreach (var buffer in _lstCoolings)                {                    if (!buffer.IsAvailable || !WaferManager.Instance.CheckNoWafer(buffer.Module, 0))                        continue;                    List<Hand> orderedBlade = new List<Hand>();                    if (blade0HasWaferAndNeedCooling && blade1HasWaferAndNeedCooling)                    {                        int result = CompareWaferPriority(ModuleName.EfemRobot, 0, ModuleName.EfemRobot, 1);                        if (result < 0 || (result == 0 && _efemRobot.WaferArriveTicks[1] < _efemRobot.WaferArriveTicks[0]))                        {                            orderedBlade.AddRange(new List<Hand>() { Hand.Blade2, Hand.Blade1 });                        }                        else                        {                            orderedBlade.AddRange(new List<Hand>() { Hand.Blade1, Hand.Blade2 });                        }                    }                    else                    {                        orderedBlade.Add(blade0HasWaferAndNeedCooling ? Hand.Blade1 : Hand.Blade2);                    }                    foreach (Hand placeBlade in orderedBlade)                    {                        if (_isFixAlignerAndCooling && GetWaferCountOutofLP(ModuleName.LP1) <= 1 && GetWaferCountOutofLP(ModuleName.LP2) <= 1)                        {                            int origin = WaferManager.Instance.GetWafer(ModuleName.EfemRobot, (int)placeBlade).OriginStation;                            if (origin == (int)ModuleName.LP1 && _mapLpCooling[ModuleName.LP1] != buffer.Module)                                continue;                            if (origin == (int)ModuleName.LP2 && _mapLpCooling[ModuleName.LP2] != buffer.Module)                                continue;                        }                        if (!buffer.IsReadyForPlace(ModuleName.EfemRobot, 0, placeBlade))                            continue;                        if (_efemRobot.Place(buffer.Module, 0, placeBlade))                        {                            buffer.WaitTransfer(ModuleName.EfemRobot, EnumTransferType.Place, 0);                            return;                        }                    }                }            }            if (!_efemRobot.IsAvailable)                return;            //pick from cooling            bool blade1Empty = WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 0);            bool blade2Empty = WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 1);            if (blade1Empty || blade2Empty)            {                ModuleName pickBuffer = ModuleName.System;                int preOriginSlot = int.MaxValue;                string prePj = string.Empty;                int preWaferCountInPm = 0;                foreach (var schedulerBuffer in _lstCoolings)                {                    if (!schedulerBuffer.IsAvailable                        || WaferManager.Instance.CheckNoWafer(schedulerBuffer.Module, 0)                        || CheckWaferNeedCooling(schedulerBuffer.Module, 0))                        continue;                    WaferInfo wafer = WaferManager.Instance.GetWafer(schedulerBuffer.Module, 0);                    bool pickAllowed = CheckWaferHasAvailableTarget(schedulerBuffer.Module, 0);                    if (!pickAllowed)                        continue;                    if ((pickBuffer == ModuleName.System)                        || (wafer.OriginSlot < preOriginSlot && prePj == wafer.ProcessJob.Name)                        || (GetProcessingWaferCount(wafer.ProcessJob.Name) < preWaferCountInPm))                    {                        preOriginSlot = wafer.OriginSlot;                        pickBuffer = schedulerBuffer.Module;                        prePj = wafer.ProcessJob.Name;                        preWaferCountInPm = GetProcessingWaferCount(prePj);                        continue;                    }                }                if (pickBuffer != ModuleName.System)                {                    SchedulerModule buffer = GetModule(pickBuffer.ToString());                    Hand pickBlade = blade1Empty ? Hand.Blade1 : Hand.Blade2;                    if (buffer.IsReadyForPick(ModuleName.EfemRobot, 0, pickBlade))                    {                        if (_efemRobot.Pick(buffer.Module, 0, pickBlade))                        {                            buffer.WaitTransfer(ModuleName.EfemRobot, EnumTransferType.Pick, 0);                            return;                        }                    }                }            }        }        private void MonitorEfemRobotGotoTask()        {            if (!_efemRobot.IsAvailable)                return;            SchedulerPM gotoPm = null;            int gotoSlot = Int32.MaxValue;            int gotoModule = -1;            foreach (var pm in _lstPms)            {                WaferInfo wafer = WaferManager.Instance.GetWafer(pm.Module, 0);                if (wafer.IsEmpty)                    continue;                if (gotoPm == null)                {                    gotoPm = pm;                    gotoModule = wafer.OriginStation;                    gotoSlot = wafer.OriginSlot;                    continue;                }                if (wafer.OriginSlot < gotoSlot && gotoModule == wafer.OriginStation)                {                    gotoSlot = wafer.OriginSlot;                    gotoPm = pm;                }            }            if (gotoPm != null)            {                if (_efemRobot.PreviousTarget == gotoPm.Module)                    return;                if (_efemRobot.Goto(gotoPm.Module, 0))                {                    return;                }            }        }        private void MonitorPMTask()        {            bool robotWaferAssigned = false;            bool aligner1WaferAssigned = false;            bool aligner2WaferAssigned = false;            foreach (var pm in _lstPms)            {                if (!pm.IsAvailable)                    continue;                if (WaferManager.Instance.CheckHasWafer(pm.Module, 0))                {                    if (CheckWaferNeedProcess(pm.Module, 0, pm.Module))                    {                        WaferInfo wafer = WaferManager.Instance.GetWafer(pm.Module, 0);                        var recipeName = pm.Module == ModuleName.PMA                            ? wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter["PMARecipe"]                            : wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter["PMBRecipe"];                        if (pm.Process((string)recipeName, false, true, wafer))                        {                            WaferManager.Instance.GetWafer(pm.Module, 0).NextSequenceStep++;                            continue;                        }                    }                    else                    {                        if (!pm.IsReadyForPick(ModuleName.EfemRobot, 0, Hand.Blade1))                        {                            pm.PrepareTransfer(ModuleName.EfemRobot, EnumTransferType.Pick, 0);                        }                    }                }                else //no wafer                {                    if (WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 0)                        && WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 1)                        && WaferManager.Instance.CheckNoWafer(ModuleName.Aligner1, 0)                        && WaferManager.Instance.CheckNoWafer(ModuleName.Aligner2, 0))                    {                        ModuleName source = ModuleName.System;                        if (_isFixAlignerAndCooling)                        {                            foreach (var moduleName in _mapLpPm)                            {                                if (moduleName.Value == pm.Module)                                    source = moduleName.Key;                            }                        }                        SlotItem item = GetNextWaferInJobQueue(source);                        if (item != null && CheckWaferNeedProcess(item.Module, item.Slot, pm.Module))                        {                            if (GetWaferTemperatureSetInRecipe(item.Module, item.Slot, pm.Module, out float temp) && !pm.IsTemperatureReady(temp))                            {                                pm.Preheating(temp);                                continue;                            }                        }                    }                    if (!pm.IsAvailable)                        continue;                    if (!robotWaferAssigned                         && CheckWaferNeedProcess(ModuleName.EfemRobot, 0, pm.Module)                         && CheckWaferNextProcessIn(ModuleName.EfemRobot, 0, pm.Module))                    {                        robotWaferAssigned = true;                        GetWaferTemperatureSetInRecipe(ModuleName.EfemRobot, 0, pm.Module, out float temp);                        bool alreadyPrepare = false;                        foreach (var schedulerPm in _lstPms)                        {                            if (schedulerPm.IsPrepareTransfer(ModuleName.EfemRobot, EnumTransferType.Place, 0)                                || (!_efemRobot.IsAvailable)                                || (schedulerPm.IsAvailable && WaferManager.Instance.CheckNoWafer(pm.Module, 0) && pm.IsReadyForPlace(ModuleName.EfemRobot, 0, Hand.Blade1)))                                alreadyPrepare = true;                        }                        if (!alreadyPrepare)                        {                            if (!pm.IsReadyForPlace(ModuleName.EfemRobot, 0, Hand.Blade1) || !pm.IsTemperatureReady(temp))                            {                                pm.PrepareTransfer(ModuleName.EfemRobot, EnumTransferType.Place, 0, temp, Hand.Blade1, WaferManager.Instance.GetWafer(ModuleName.EfemRobot, 0).Size);                            }                        }                    }                    if (!pm.IsAvailable)                        continue;                    if (!robotWaferAssigned                        && CheckWaferNeedProcess(ModuleName.EfemRobot, 1, pm.Module)                        && CheckWaferNextProcessIn(ModuleName.EfemRobot, 1, pm.Module))                    {                        robotWaferAssigned = true;                        GetWaferTemperatureSetInRecipe(ModuleName.EfemRobot, 1, pm.Module, out float temp);                        bool alreadyPrepare = false;                        foreach (var schedulerPm in _lstPms)                        {                            if (schedulerPm.IsPrepareTransfer(ModuleName.EfemRobot, EnumTransferType.Place, 0)                                || (!_efemRobot.IsAvailable)                                || (schedulerPm.IsAvailable && WaferManager.Instance.CheckNoWafer(pm.Module, 0) && pm.IsReadyForPlace(ModuleName.EfemRobot, 0, Hand.Blade2)))                                alreadyPrepare = true;                        }                        if (!alreadyPrepare)                        {                            if (!pm.IsReadyForPlace(ModuleName.EfemRobot, 0, Hand.Blade2) ||                                !pm.IsTemperatureReady(temp))                            {                                pm.PrepareTransfer(ModuleName.EfemRobot, EnumTransferType.Place, 0, temp, Hand.Blade2,                                    WaferManager.Instance.GetWafer(ModuleName.EfemRobot, 1).Size);                            }                        }                    }                    if (!pm.IsAvailable)                        continue;                    //并行模式下,避免提前预判aligner的wafer位置                    if (_isRunningInParallelMode)                         continue;                    if (!aligner1WaferAssigned && CheckWaferNeedProcess(ModuleName.Aligner1, 0, pm.Module))                    {                        aligner1WaferAssigned = true;                        GetWaferTemperatureSetInRecipe(ModuleName.Aligner1, 0, pm.Module, out float temp);                        bool alreadyPrepare = false;                        foreach (var schedulerPm in _lstPms)                        {                            if (schedulerPm.IsPrepareTransfer(ModuleName.EfemRobot, EnumTransferType.Place, 0)                                || (!_efemRobot.IsAvailable)                                || (schedulerPm.IsAvailable && WaferManager.Instance.CheckNoWafer(pm.Module, 0) && pm.IsReadyForPlace(ModuleName.EfemRobot, 0, Hand.Blade1)))                                alreadyPrepare = true;                        }                        if (!alreadyPrepare)                        {                            if (!pm.IsReadyForPlace(ModuleName.EfemRobot, 0, Hand.Blade1) ||                                !pm.IsTemperatureReady(temp))                            {                                pm.PrepareTransfer(ModuleName.EfemRobot, EnumTransferType.Place, 0, temp, Hand.Blade1,                                    WaferManager.Instance.GetWafer(ModuleName.Aligner1, 0).Size);                            }                        }                    }                    if (!pm.IsAvailable)                        continue;                    if (!aligner2WaferAssigned && CheckWaferNeedProcess(ModuleName.Aligner2, 0, pm.Module))                    {                        aligner2WaferAssigned = true;                        GetWaferTemperatureSetInRecipe(ModuleName.Aligner2, 0, pm.Module, out float temp);                        bool alreadyPrepare = false;                        foreach (var schedulerPm in _lstPms)                        {                            if (schedulerPm.IsPrepareTransfer(ModuleName.EfemRobot, EnumTransferType.Place, 0)                                || (!_efemRobot.IsAvailable)                                || (schedulerPm.IsAvailable && WaferManager.Instance.CheckNoWafer(pm.Module, 0) && pm.IsReadyForPlace(ModuleName.EfemRobot, 0, Hand.Blade1)))                                alreadyPrepare = true;                        }                        if (!alreadyPrepare)                        {                            if (!pm.IsReadyForPlace(ModuleName.EfemRobot, 0, Hand.Blade1) ||                                !pm.IsTemperatureReady(temp))                            {                                pm.PrepareTransfer(ModuleName.EfemRobot, EnumTransferType.Place, 0, temp, Hand.Blade1,                                    WaferManager.Instance.GetWafer(ModuleName.Aligner2, 0).Size);                            }                        }                    }                    if (!pm.IsAvailable)                        continue;                }            }        }        #endregion Module task        #region Logic Check        private bool CheckSequencePmReady(SequenceInfo seq, List<ModuleName> pmOccupied, out List<ModuleName> pmUsed, out string reason)        {            pmUsed = new List<ModuleName>();            reason = "";            bool pmIsReady = true;            for (int i = 0; i < seq.Steps.Count; i++)            {                SequenceStepInfo stepInfo = seq.Steps[i];                bool hasPm = false;                foreach (var module in stepInfo.StepModules)                {                    if (!ModuleHelper.IsPm(module))                    {                        hasPm = true;                        break;                    }                    PM pm = DEVICE.GetDevice<PM>(module.ToString());                    if (pm.IsInstalled && (pmOccupied == null || !pmOccupied.Contains(module)))                    {                        hasPm = true;                    }                    if (!pmUsed.Contains(module))                        pmUsed.Add(module);                }                if (pmIsReady && !hasPm)                {                    reason = $"Step {i + 1} no valid PM, " + string.Join("|", stepInfo.StepModules);                    pmIsReady = false;                }            }            return pmIsReady;        }        private bool CheckSequenceOrderOk(SequenceInfo seq, out string reason)        {            reason = "";            bool foundPm = false;            bool isAlignerAfterPm = false;            for (int i = 0; i < seq.Steps.Count; i++)            {                SequenceStepInfo stepInfo = seq.Steps[i];                foreach (var module in stepInfo.StepModules)                {                    if (ModuleHelper.IsPm(module))                    {                        foundPm = true;                    }                    if (ModuleHelper.IsAligner(module) && foundPm)                    {                        isAlignerAfterPm = true;                    }                }            }            if (!foundPm)            {                reason = $"not found PM in the sequence file;";            }            if (isAlignerAfterPm)            {                reason += "Aligner after PM not support";            }            return true;        }        protected int GetUnprocessedWaferCount()        {            int count = 0;            foreach (ProcessJobInfo pj in _lstProcessJobs)            {                if (pj.State == EnumProcessJobState.Processing || pj.State == EnumProcessJobState.Paused)                    count += GetUnprocessedWaferCount(pj);            }            return count;        }        protected int GetUnprocessedWaferCount(ProcessJobInfo pj)        {            int count = 0;            for (int i = 0; i < pj.SlotWafers.Count; ++i)            {                WaferInfo wafer = WaferManager.Instance.GetWafer(pj.SlotWafers[i].Item1, pj.SlotWafers[i].Item2);                if (wafer.IsEmpty)                    continue;                if (CheckWaferNeedProcess(pj.SlotWafers[i].Item1, pj.SlotWafers[i].Item2))                    count++;            }            return count;        }        protected bool CheckAllWaferReturned(ProcessJobInfo pj, bool checkAllProcessed)        {            for (int i = 0; i < pj.SlotWafers.Count; ++i)            {                WaferInfo wafer = WaferManager.Instance.GetWafer(pj.SlotWafers[i].Item1, pj.SlotWafers[i].Item2);                if (wafer.IsEmpty)                    return false;                if (checkAllProcessed && CheckWaferNeedProcess(pj.SlotWafers[i].Item1, pj.SlotWafers[i].Item2))                    return false;            }            return true;        }        private bool CheckWaferNextStepIsAlign(ModuleName module, int slot)        {            if (!WaferManager.Instance.CheckHasWafer(module, slot))                return false;            WaferInfo wafer = WaferManager.Instance.GetWafer(module, slot);            if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)                return false;            if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)                return false;            if (wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(ModuleName.Aligner1)                || wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(ModuleName.Aligner2))                return true;            return false;        }        private bool CheckWaferNextStepIsCooling(ModuleName module, int slot)        {            if (!WaferManager.Instance.CheckHasWafer(module, slot))                return false;            WaferInfo wafer = WaferManager.Instance.GetWafer(module, slot);            if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)                return false;            if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)                return false;            if (wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(ModuleName.Cooling1)                || wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(ModuleName.Cooling2))                return true;            return false;        }        private bool GetWaferTemperatureSetInRecipe(ModuleName waferModule, int waferSlot, ModuleName pmModule, out float temp)        {            WaferInfo wafer = WaferManager.Instance.GetWafer(waferModule, waferSlot);            var seq = wafer.ProcessJob.Sequence;            for (int i = 0; i < seq.Steps.Count; i++)            {                SequenceStepInfo stepInfo = seq.Steps[i];                foreach (var module in stepInfo.StepModules)                {                    if (module == pmModule)                    {                        temp = (float)seq.Steps[i].StepParameter[module == ModuleName.PMA ? "PMATemp" : "PMBTemp"];                        return true;                    }                }            }            temp = 0;            LOG.Error($"Can not find wafer {waferModule} {waferSlot + 1} temperature set in recipe");            return false;        }        private bool CheckWaferPmTemperatureIsOk(ModuleName waferModule, int waferSlot)        {            WaferInfo wafer = WaferManager.Instance.GetWafer(waferModule, waferSlot);            if (wafer.IsEmpty || wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)                return false;            var seq = wafer.ProcessJob.Sequence;            for (int i = 0; i < seq.Steps.Count; i++)            {                SequenceStepInfo stepInfo = seq.Steps[i];                bool stepOk = false;                foreach (var module in stepInfo.StepModules)                {                    if (ModuleHelper.IsPm(module))                    {                        float tempNeeded = (float)seq.Steps[i].StepParameter[module == ModuleName.PMA ? "PMATemp" : "PMBTemp"];                        if ((GetModule(module.ToString()) as SchedulerPM).IsTemperatureReady(tempNeeded))                        {                            stepOk = true;                            break;                        }                    }                    else                    {                        stepOk = true;                    }                }                if (!stepOk)                    return false;            }            return true;        }        protected bool CheckWaferNeedAlign(ModuleName waferModule, int waferSlot)        {            WaferInfo wafer = WaferManager.Instance.GetWafer(waferModule, 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;            if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules                    .Contains(ModuleName.Aligner1) && !wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules                    .Contains(ModuleName.Aligner2))                return false;            return true;        }        private bool CheckWaferNeedCooling(ModuleName waferModule, int waferSlot)        {            WaferInfo wafer = WaferManager.Instance.GetWafer(waferModule, 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;            if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules                .Contains(ModuleName.Cooling1) && !wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules                .Contains(ModuleName.Cooling2))                return false;            return true;        }        private bool CheckWaferNextProcessIn(ModuleName waferModule, int waferSlot, ModuleName chamber)        {            WaferInfo wafer = WaferManager.Instance.GetWafer(waferModule, waferSlot);            if (wafer.IsEmpty ||                wafer.ProcessJob == null ||                wafer.ProcessJob.Sequence == null ||                wafer.ProcessJob.Sequence.Steps == null ||                wafer.ProcessJob.Sequence.Steps.Count <= wafer.NextSequenceStep ||                wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep] == null ||                wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules == null)            {                return false;            }            if (_isFixAlignerAndCooling && _mapLpPm[(ModuleName)wafer.OriginStation] != chamber)                return false;            return wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(chamber);        }        public bool CheckWaferNeedProcessAndPMAvailable(ModuleName waferModule, int waferSlot, ModuleName processIn = ModuleName.System)        {            WaferInfo wafer = WaferManager.Instance.GetWafer(waferModule, 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;            for (int i = wafer.NextSequenceStep; i < wafer.ProcessJob.Sequence.Steps.Count; i++)            {                if (wafer.ProcessJob.Sequence.Steps[i].StepModules                        .Contains(ModuleName.PMA) || wafer.ProcessJob.Sequence.Steps[i].StepModules                        .Contains(ModuleName.PMB))                {                    var hasPmAvailable = false;                    foreach (var stepModule in wafer.ProcessJob.Sequence.Steps[i].StepModules)                    {                        var pm = GetModule(stepModule.ToString()) as SchedulerPM;                        if (pm != null)                        {                            if (pm.IsAvailable || (pm.IsOnline && pm.Task != SchedulerModule.TaskType.PreJobProcess))                            {                                hasPmAvailable = true;                                break;                            }                        }                    }                    if (!hasPmAvailable)                        return false;                    if (processIn == ModuleName.System)                        return true;                    if (_isFixAlignerAndCooling && _mapLpPm[(ModuleName)wafer.OriginStation] != processIn)                        return false;                    if (wafer.ProcessJob.Sequence.Steps[i].StepModules                        .Contains(processIn))                        return true;                }            }            return false;        }        public bool CheckWaferNeedProcess(ModuleName waferModule, int waferSlot, ModuleName processIn = ModuleName.System)        {            WaferInfo wafer = WaferManager.Instance.GetWafer(waferModule, 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;            for (int i = wafer.NextSequenceStep; i < wafer.ProcessJob.Sequence.Steps.Count; i++)            {                if (wafer.ProcessJob.Sequence.Steps[i].StepModules                        .Contains(ModuleName.PMA) || wafer.ProcessJob.Sequence.Steps[i].StepModules                        .Contains(ModuleName.PMB))                {                    if (processIn == ModuleName.System)                        return true;                    if (_isFixAlignerAndCooling && _mapLpPm[(ModuleName)wafer.OriginStation] != processIn)                        return false;                    if (wafer.ProcessJob.Sequence.Steps[i].StepModules                        .Contains(processIn))                        return true;                }            }            return false;        }        private bool CheckVacuumWaferHasAvailableTarget(ModuleName waferModule, int waferSlot)        {            WaferInfo wafer = WaferManager.Instance.GetWafer(waferModule, waferSlot);            //System.Diagnostics.Trace.Assert(!wafer.IsEmpty);            //if (CheckWaferNeedProcess(waferModule, waferSlot))            //{            //    // Check for an empty PM            //    foreach (var pm in _lstPms)            //    {            //        if (WaferManager.Instance.CheckNoWafer(pm.Module, 0))            //        {            //            if (pm.IsAvailable == false)            //                continue;            //            if (!CheckWaferNextProcessIn(waferModule, waferSlot, pm.Module))            //                continue;            //            return true;            //        }            //    }            //}            //else            {                // No more processing needed, check for a outbound BUFFER slot                foreach (var buffer in _lstCoolings)                {                    if (!buffer.IsAvailable)                        continue;                    if (WaferManager.Instance.CheckNoWafer(buffer.Module, 0))                    {                        return true;                    }                }            }            return false;        }        private bool CheckWaferHasAvailableTarget(ModuleName waferModule, int waferSlot)        {            WaferInfo wafer = WaferManager.Instance.GetWafer(waferModule, waferSlot);            if (wafer.IsEmpty)                return false;            if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)                return false;            //sequence done, return LP            if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)                return true;            foreach (var stepModule in wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules)            {                if (WaferManager.Instance.CheckNoWafer(stepModule, 0))                    return true;            }            return false;        }        private bool CheckBufferWaferHasAvailableTarget(ModuleName waferModule, int waferSlot)        {            WaferInfo wafer = WaferManager.Instance.GetWafer(waferModule, waferSlot);            //System.Diagnostics.Trace.Assert(!wafer.IsEmpty);            if (!CheckWaferNeedProcess(waferModule, waferSlot))                return true;            // Check for an empty PM            foreach (var pm in _lstPms)            {                if (WaferManager.Instance.CheckNoWafer(pm.Module, 0))                {                    if (pm.IsAvailable == false)                        continue;                    if (!CheckWaferNextProcessIn(waferModule, waferSlot, pm.Module))                        continue;                    return true;                }            }            return false;        }        private bool SetSequenceTemperatureInfo(SequenceInfo seq, out string reason)        {            for (int i = 0; i < seq.Steps.Count; i++)            {                SequenceStepInfo stepInfo = seq.Steps[i];                foreach (var module in stepInfo.StepModules)                {                    if (ModuleHelper.IsPm(module))                    {                        string attr = module == ModuleName.PMA ? "PMARecipe" : "PMBRecipe";                        if (stepInfo.StepParameter.ContainsKey(attr)                            && !string.IsNullOrEmpty((string)stepInfo.StepParameter[attr]))                        {                            var recipeName = (string)stepInfo.StepParameter[attr];                            if (!string.IsNullOrEmpty(recipeName))                            {                                var recipeContent =                                    RecipeFileManager.Instance.LoadRecipe($"", recipeName, false);                                if (string.IsNullOrEmpty(recipeContent))                                {                                    reason = $"Can not find recipe file{recipeName}";                                    return false;                                }                                try                                {                                    XmlDocument xml = new XmlDocument();                                    xml.LoadXml(recipeContent);                                    var substrateTemp = xml.DocumentElement.HasAttribute("SubstrateTemp") ? xml.DocumentElement.Attributes["SubstrateTemp"].Value : "";                                    if (!float.TryParse(substrateTemp, out float temp))                                    {                                        reason = $"Invalid substrate temperature in recipe head {recipeName}";                                        return false;                                    }                                    seq.Steps[i].StepParameter[module == ModuleName.PMA ? "PMATemp" : "PMBTemp"] = temp;                                }                                catch (Exception ex)                                {                                    LOG.Write(ex);                                    reason = $"recipe not valid, {recipeName}";                                    return false;                                }                            }                        }                    }                }            }            reason = "";            return true;        }        private bool CheckSequenceRecipeFileValid(SequenceInfo seq, out string reason)        {            for (int i = 0; i < seq.Steps.Count; i++)            {                SequenceStepInfo stepInfo = seq.Steps[i];                foreach (var module in stepInfo.StepModules)                {                    if (ModuleHelper.IsPm(module))                    {                        string attr = module == ModuleName.PMA ? "PMARecipe" : "PMBRecipe";                        if (stepInfo.StepParameter.ContainsKey(attr)                            && !string.IsNullOrEmpty((string)stepInfo.StepParameter[attr]))                        {                            var recipeName = (string)stepInfo.StepParameter[attr];                            if (!string.IsNullOrEmpty(recipeName))                            {                                var recipeContent =                                    RecipeFileManager.Instance.LoadRecipe($"", recipeName, false);                                if (string.IsNullOrEmpty(recipeContent))                                {                                    reason = $"Can not find recipe file{recipeName}";                                    return false;                                }                            }                        }                    }                }            }            reason = "";            return true;        }        private bool GetWaferSequenceAlignTime(ModuleName module, int slot, out float time)        {            time = 0;            if (!WaferManager.Instance.CheckHasWafer(module, slot))                return false;            WaferInfo wafer = WaferManager.Instance.GetWafer(module, slot);            if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)                return false;            if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)                return false;            if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(ModuleName.Aligner1)                && !wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(ModuleName.Aligner2)                && !wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(ModuleName.Cooling1)                && !wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(ModuleName.Cooling2))                return false;            if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter.ContainsKey("CoolingTime"))                return false;            if (!float.TryParse((string)wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter["CoolingTime"],                out time))                return false;            return true;        }        private int GetWaferCountOutofLP(ModuleName lp)        {            int count = 0;            var lstPosition = new List<ModuleName>()            {                ModuleName.EfemRobot, ModuleName.Aligner1, ModuleName.Aligner2, ModuleName.Cooling1, ModuleName.Cooling2, ModuleName.PMA, ModuleName.PMB,            };            foreach (var moduleName in lstPosition)            {                if (ModuleHelper.IsPm(moduleName) && !GetModule(moduleName.ToString()).IsOnline)                    continue;                if (WaferManager.Instance.CheckHasWafer(moduleName, 0))                {                    if (lp == ModuleName.System ||                        WaferManager.Instance.GetWafer(moduleName, 0).OriginStation == (int)lp)                        count++;                }            }            if (WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 1))            {                if (lp == ModuleName.System ||                    WaferManager.Instance.GetWafer(ModuleName.EfemRobot, 1).OriginStation == (int)lp)                    count++;            }            return count;        }        private SlotItem GetWaferReturnLoadPort(ModuleName module, int slot)        {            WaferInfo wafer = WaferManager.Instance.GetWafer(module, slot);            if (!wafer.IsEmpty)            {                return new SlotItem((ModuleName)wafer.OriginStation, wafer.OriginSlot);            }            return null;        }        private int GetWaferCountInJobQueue(ModuleName sourceLp)        {            int count = 0;            foreach (var lp in _lstLps)            {                for (int i = 0; i < 25; i++)                {                    if (CheckWaferNeedProcess(lp.Module, i) && (sourceLp == ModuleName.System || sourceLp == lp.Module))                        count++;                }            }            return count;        }        /// <summary>        /// 获取下一个Wafer。根据某个LP,或者任意LP        /// </summary>        /// <param name="lpModule">如果是System,表示查询的时候根据任意LoadPort</param>        /// <returns></returns>        protected SlotItem GetNextWaferInJobQueue(ModuleName lpModule)        {            if (!_isRunningInParallelMode)            {                foreach (var cj in _lstControlJobs)                {                    if (lpModule != ModuleName.System && (cj.Module != lpModule.ToString()))                        continue;                    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 (CheckWaferNeedProcessAndPMAvailable(pjSlotWafer.Item1, pjSlotWafer.Item2))                                        return new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2);                                }                            }                        }                    }                }                return null;            }            //parallel mode             Dictionary<string, SlotItem> pjWafer = new Dictionary<string, SlotItem>();            Dictionary<string, List<ModuleName>> pmUsed = new Dictionary<string, List<ModuleName>>();            foreach (var cj in _lstControlJobs)            {                if (cj.State != EnumControlJobState.Executing)                    continue;                foreach (var pj in _lstProcessJobs)                {                    if (pj.ControlJobName == cj.Name && pj.State == EnumProcessJobState.Processing)                    {                        foreach (var pjSlotWafer in pj.SlotWafers)                        {                            if (CheckWaferNeedProcessAndPMAvailable(pjSlotWafer.Item1, pjSlotWafer.Item2))                            {                                pjWafer[pj.Name] = new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2);                                break;                            }                        }                    }                }            }            if (pjWafer.Count == 0)                return null;            if (pjWafer.Count == 1)                return pjWafer.Values.First();            string preferPj = pjWafer.Keys.First();            int runningWaferCount = GetWaitingProcessWaferCount(preferPj);            foreach (var slotItem in pjWafer)            {                if (slotItem.Key == preferPj)                    continue;                int count = GetWaitingProcessWaferCount(slotItem.Key);                if (count < runningWaferCount)                {                    preferPj = slotItem.Key;                    runningWaferCount = count;                }            }            return pjWafer[preferPj];        }        private int GetWaitingProcessWaferCount(string pjName)        {            List<Tuple<ModuleName, int>> location = new List<Tuple<ModuleName, int>>()            {                Tuple.Create(ModuleName.EfemRobot, 0),                Tuple.Create(ModuleName.EfemRobot, 1),                Tuple.Create(ModuleName.Aligner1, 0),                Tuple.Create(ModuleName.Aligner2, 0),                Tuple.Create(ModuleName.PMA, 0),                Tuple.Create(ModuleName.PMB, 0),            };            int count = 0;            foreach (var tuple in location)            {                if (ModuleHelper.IsPm(tuple.Item1) && !GetModule(tuple.Item1.ToString()).IsOnline)                    continue;                WaferInfo wafer = WaferManager.Instance.GetWafer(tuple.Item1, tuple.Item2);                if (wafer.IsEmpty)                    continue;                if (wafer.ProcessJob != null && wafer.ProcessJob.Name == pjName)                    count++;            }            return count;        }        private int GetCoolingWaferCount(string pjName)        {            List<Tuple<ModuleName, int>> location = new List<Tuple<ModuleName, int>>()            {                Tuple.Create(ModuleName.Cooling1, 0),                Tuple.Create(ModuleName.Cooling2, 0),            };            int count = 0;            foreach (var tuple in location)            {                WaferInfo wafer = WaferManager.Instance.GetWafer(tuple.Item1, tuple.Item2);                if (wafer.IsEmpty)                    continue;                if (wafer.ProcessJob != null && wafer.ProcessJob.Name == pjName)                    count++;            }            return count;        }        private int GetProcessingWaferCount(string pjName)        {            List<Tuple<ModuleName, int>> location = new List<Tuple<ModuleName, int>>()            {                Tuple.Create(ModuleName.PMA, 0),                Tuple.Create(ModuleName.PMB, 0),            };            int count = 0;            foreach (var tuple in location)            {                if (ModuleHelper.IsPm(tuple.Item1) && !GetModule(tuple.Item1.ToString()).IsOnline)                    continue;                WaferInfo wafer = WaferManager.Instance.GetWafer(tuple.Item1, tuple.Item2);                if (wafer.IsEmpty)                    continue;                if (wafer.ProcessJob != null && wafer.ProcessJob.Name == pjName)                    count++;            }            return count;        }        private List<ModuleName> GetPmUsedInRunningPj()        {            var pmUsed = new List<ModuleName>();            foreach (var cj in _lstControlJobs)            {                if (cj.State != EnumControlJobState.Executing && cj.State != EnumControlJobState.Paused)                    continue;                foreach (var pj in _lstProcessJobs)                {                    if (pj.ControlJobName == cj.Name && (pj.State == EnumProcessJobState.Processing || pj.State == EnumProcessJobState.Paused))                    {                        for (int i = 0; i < pj.Sequence.Steps.Count; i++)                        {                            SequenceStepInfo stepInfo = pj.Sequence.Steps[i];                            foreach (var module in stepInfo.StepModules)                            {                                if (ModuleHelper.IsPm(module) && !pmUsed.Contains(module))                                    pmUsed.Add(module);                            }                        }                    }                }            }            return pmUsed;        }        private int CompareWaferPriority(ModuleName module1, int slot1, ModuleName module2, int slot2)        {            if (module1 == ModuleName.System || module2 == ModuleName.System)                return 0;            WaferInfo wafer1 = WaferManager.Instance.GetWafer(module1, slot1);            WaferInfo wafer2 = WaferManager.Instance.GetWafer(module2, slot2);            if (wafer1.IsEmpty || wafer2.IsEmpty)                return 0;            if (wafer1.Size != wafer2.Size)                return 0;            //same process job && same load port            if (_lstProcessJobs.Exists(x => x.SlotWafers.Exists(y => y.Item1 == (ModuleName)wafer1.OriginStation && y.Item2 == wafer1.OriginSlot)                                            && x.SlotWafers.Exists((y =>                                                y.Item1 == (ModuleName)wafer2.OriginStation && y.Item2 == wafer2.OriginSlot)))                && (wafer1.OriginStation == wafer2.OriginStation))            {                //lower number slot has high priority                return wafer2.OriginSlot - wafer1.OriginSlot;            }            return 0;        }        private List<SchedulerPM> GetPmNeeded(ControlJobInfo cj)        {            List<SchedulerPM> result = new List<SchedulerPM>();            foreach (var pj in _lstProcessJobs)            {                if (pj.ControlJobName != cj.Name)                    continue;                var seq = pj.Sequence;                for (int i = 0; i < seq.Steps.Count; i++)                {                    SequenceStepInfo stepInfo = seq.Steps[i];                    foreach (var module in stepInfo.StepModules)                    {                        if (ModuleHelper.IsPm(module))                        {                            var pm = _lstPms.Find(x => x.Module == module);                            if (pm != null && !result.Contains(pm))                            {                                result.Add(pm);                            }                        }                    }                }            }            return result;        }        public bool CheckRecipeUsedInJob(string pathName)        {            foreach (var pj in _lstProcessJobs)            {                var seq = pj.Sequence;                for (int i = 0; i < seq.Steps.Count; i++)                {                    SequenceStepInfo stepInfo = seq.Steps[i];                    foreach (var module in stepInfo.StepModules)                    {                        if (ModuleHelper.IsPm(module))                        {                            string attr = module == ModuleName.PMA ? "PMARecipe" : "PMBRecipe";                            if (stepInfo.StepParameter.ContainsKey(attr)                                && !string.IsNullOrEmpty((string)stepInfo.StepParameter[attr]))                            {                                var recipeName = (string)stepInfo.StepParameter[attr];                                if (!string.IsNullOrEmpty(recipeName))                                {                                    if (pathName.EndsWith(recipeName+".rcp"))                                        return true;                                }                            }                        }                    }                }            }            return false;        }        public bool CheckSequenceUsedInJob(string pathName)        {            foreach (var pj in _lstProcessJobs)            {                if (pathName.EndsWith(pj.Sequence.Name+".seq"))                    return true;            }            return false;        }        #endregion Logic Check    }}
 |