| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401 | using System;using System.Collections;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Aitex.Core.RT.Fsm;using Aitex.Core.Common;using Aitex.Core.RT.DataCenter;using Aitex.Core.RT.Event;using Aitex.Core.RT.OperationCenter;using Aitex.Core.RT.SCCore;using Aitex.Core.Util;using MECF.Framework.Common.Jobs;using MECF.Framework.Common.Equipment;using MECF.Framework.Common.SubstrateTrackings;using CyberX8_Core;using Aitex.Core.RT.Log;using SecsGem.Core.Application;using CyberX8_RT.Modules.SRD;using CyberX8_RT.Modules.PUF;using CyberX8_RT.Modules.Dummy;using CyberX8_RT.Modules.Loader;using Aitex.Core.RT.Device;using CyberX8_RT.Modules.Prewet;using CyberX8_RT.Modules.Dryer;using MECF.Framework.Common.ToolLayout;using CyberX8_RT.Modules.Metal;using CyberX8_RT.Modules.Rinse;using MECF.Framework.Common.Routine;using CyberX8_RT.Dispatch;using CyberX8_RT.Modules.Reservoir;using System.IO;using CyberX8_RT.Modules.Buffer;using CyberX8_RT.Modules.Transporter;using CyberX8_RT.Devices.Loader;using CyberX8_RT.Devices.PUF;using CyberX8_RT.Devices.SRD;using MECF.Framework.Common.Alarm;using System.Diagnostics;using MECF.Framework.Common.WaferHolder;using CyberX8_RT.Schedulers;using MECF.Framework.Common.ProcessCell;using System.Reflection;namespace CyberX8_RT.Modules{    class RouteManager : Entity, IEntity    {        public enum MSG        {            MoveWafer,            ReturnWafer,            HomeUnit,            PauseAuto,            ResumeAuto,            Stop,            StartCycle,            StopCycle,            HOME,            RESET,            ABORT,            ERROR,            SetAutoMode,            SetManualMode,            ResetIdleCleanTime,            ResetIdlePurgeTime,            CreateJob,            PauseJob,            PauseAllJobs,            ResumeJob,            ResumeAllJobs,            StartJob,            StopJob,            AbortJob,            JobDone,            CassetteLeave,  //For unload light control off afer job done            Map,            ReturnAllWafer,            TMCycle,                        Retry,            ConfirmComplete,            ResetWafers,            FaStartJob,            FaStopJob,        }        #region 属性        public string Name { get; set; }        public bool IsAutoMode        {            get            {                return fsm.State == (int)RtState.AutoRunning || fsm.State == (int)RtState.AutoIdle||fsm.State==(int)RtState.AutoAborting;            }        }        public bool IsFaAutoMode        {            get            {                return fsm.State == (int)RtState.AutoRunning || fsm.State == (int)RtState.AutoIdle;            }        }        public bool IsInit        {            get { return fsm.State == (int)RtState.Init; }        }        public bool IsIdle        {            get { return fsm.State == (int)RtState.Idle || fsm.State == (int)RtState.AutoIdle; }        }        public bool IsAlarm        {            get { return fsm.State == (int)RtState.Error; }        }        public bool IsPaused        {            get { return _jobCycle.CycleState == RState.Paused; }        }        public bool IsRunning        {            get            {                return !IsInit && !IsAlarm && !IsIdle;            }        }        /// <summary>        /// 是否AutoRunning        /// </summary>        public bool IsAutoRunning        {            get { return fsm.State == (int)RtState.AutoRunning||fsm.State==(int)RtState.AutoAborting; }        }        /// <summary>        /// 是否        /// </summary>        public bool IsAutoIdle        {            get { return fsm.State == (int)RtState.AutoIdle; }        }        /// <summary>        /// EFEM实体        /// </summary>        public EfemEntity EFEM { get; }        public WaferSize WaferSize { get; private set; }        #endregion        #region 内部变量        private string _systemControlIp;        private ICycle _jobCycle;        private ModuleHomeAllRoutine _homeAllRoutine;        private List<ReservoirMetalHomeRoutine> _reservoirMetalRoutines=new List<ReservoirMetalHomeRoutine>();        /// <summary>        /// 模块实体字典        /// </summary>        private Dictionary<string, IModuleEntity> _moduleEntitiesDic = new Dictionary<string, IModuleEntity>();        /// <summary>        /// 模块类型实体字典        /// </summary>        private Dictionary<ModuleType, List<IModuleEntity>> _modultTypeEntitiesDic = new Dictionary<ModuleType, List<IModuleEntity>>();        /// <summary>        /// Home stopwatch        /// </summary>        private Stopwatch _homeStopWatch = new Stopwatch();        #endregion        /// <summary>        /// 构造函数        /// </summary>        public RouteManager()        {            Name = "System";            WaferSize = (WaferSize)SC.GetValue<int>("System.WaferSize");            if (ModuleHelper.IsInstalled(ModuleName.EFEM))            {                EFEM = new EfemEntity();                EFEM.Initialize();                _moduleEntitiesDic[ModuleName.EFEM.ToString()] = EFEM;            }            InitialModuleList(PufItemManager.Instance.InstalledModules, typeof(PUFEntity),ModuleType.PUF);            InitialModuleList(DummyCasseteItemManager.Instance.InstalledModules, typeof(DummyEntity),ModuleType.Dummy);            InitialModuleList(LoaderItemManager.Instance.InstalledModules, typeof(LoaderEntity),ModuleType.Loader);            InitialModuleList(TransporterItemManager.Instance.InstalledModules, typeof(TransporterEntity),ModuleType.Transporter);            InitialModuleList(BufferItemManager.Instance.InstalledModules, typeof(BufferEntity), ModuleType.Buffer);            InitialModuleList(PrewetItemManager.Instance.InstalledModules, typeof(PrewetEntity),ModuleType.Prewet);            InitialModuleList(DryerItemManager.Instance.InstalledModules, typeof(DryerEntity),ModuleType.Dryer);            InitialModuleList(MetalItemManager.Instance.InstalledModules, typeof(MetalEntity),ModuleType.Metal);            InitialModuleList(RinseItemManager.Instance.InstalledModules, typeof(RinseEntity),ModuleType.Rinse);            InitialModuleList(ReservoirItemManager.Instance.InstalledModules,typeof(ReservoirEntity),ModuleType.Reservoir);            InitialModuleList(SrdItemManager.Instance.InstalledModules, typeof(SRDEntity), ModuleType.SRD);            fsm = new StateMachine<RouteManager>(Name, (int)RtState.Init, 200);            SubscribeOperation();            SubscribeDataVariable();        }        /// <summary>        /// 初始化模块集合        /// </summary>        /// <param name="lst"></param>        /// <param name="entityType"></param>        private void InitialModuleList(List<string> lst,Type entityType,ModuleType moduleType)        {            foreach(string item in lst)            {                InitialModule(item, entityType,moduleType);            }        }        /// <summary>        /// 初始化模块对象        /// </summary>        /// <param name="item"></param>        /// <param name="moduleType"></param>        private void InitialModule(string item,Type entityType,ModuleType moduleType)        {            ModuleName moduleName = (ModuleName)Enum.Parse(typeof(ModuleName), item);            IModuleEntity moduleEntity= (IModuleEntity)System.Activator.CreateInstance(entityType,moduleName);            moduleEntity.Initialize();            _moduleEntitiesDic[item] = moduleEntity;            List<IModuleEntity> lst = new List<IModuleEntity>();            if(_modultTypeEntitiesDic.ContainsKey(moduleType))            {                lst= _modultTypeEntitiesDic[moduleType];            }            else            {                _modultTypeEntitiesDic[moduleType] = lst;            }            lst.Add(moduleEntity);        }        public bool Check(int msg, out string reason, params object[] args)        {            if (!fsm.FindTransition(fsm.State, msg))            {                reason = String.Format("{0} is in {1} state,can not do {2}", Name, 0, (MSG)msg);                return false;            }            if (msg == (int)MSG.StartCycle)            {                if (!IsAutoMode)                {                    reason = String.Format("can not do {0}, isn't auto mode.", msg.ToString());                    return false;                }            }            reason = "";            return true;        }        /// <summary>        /// 订阅数据        /// </summary>        void SubscribeDataVariable()        {            DATA.Subscribe("System.SystemControlIp", ()=>_systemControlIp, SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe("Rt.Status", () => ((RtState)fsm.State).ToString(), SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe("System.State", () => ((RtState)fsm.State).ToString(), SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe("System.IsAutoMode", () => IsAutoMode, SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe("System.IsAutoRunning", () => IsAutoRunning, SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe("System.IsIdle", () => IsIdle || IsInit, SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe("System.IsAlarm", () => IsAlarm, SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe("System.IsBusy", () => IsRunning, SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe("System.IsConnectedWithHost", () => CheckSecsGemOnline(Singleton<SecGemApplication>.Instance.ControlState),SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe("System.IsDisconnectWithHost", () => CheckSecsGemOnline(Singleton<SecGemApplication>.Instance.ControlState),SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe("System.EquipmentMode", () => IsAutoMode ? "Auto":"Manual", SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe("EquipmentStatus", () =>            {                if (IsInit) return 0;                if (IsIdle) return 1;                if (IsAlarm) return 3;                if (IsPaused) return 4;                return 2;            }, SubscriptionAttribute.FLAG.IgnoreSaveDB);        }        /// <summary>        /// 订阅操作        /// </summary>        void SubscribeOperation()        {            OP.Subscribe("ApplySystemControl", ApplySystemControl);            OP.Subscribe("ReleaseSystemControl", ReleaseSystemControl);            OP.Subscribe("CreateWafer", InvokeCreateWafer);            OP.Subscribe("DeleteWafer", InvokeDeleteWafer);            OP.Subscribe("System.Home", (cmd, args) => CheckToPostMessage((int)MSG.HOME, args));            DATA.Subscribe("SYSTEM.FsmState", () => (((RtState)fsm.State).ToString()), SubscriptionAttribute.FLAG.IgnoreSaveDB);            OP.Subscribe("System.ReturnAllWafer", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.ReturnAllWafer, args[0], args[1], args[2], args[3]);            });            OP.Subscribe("System.MoveWafer", (string cmd, object[] args) =>            {                if (!Enum.TryParse((string)args[0], out ModuleName source))                {                    EV.PostWarningLog(Name, $"Parameter source {(string)args[0]} not valid");                    return false;                }                if (!Enum.TryParse((string)args[2], out ModuleName destination))                {                    EV.PostWarningLog(Name, $"Parameter destination {(string)args[1]} not valid");                    return false;                }                                return CheckToPostMessage((int)MSG.MoveWafer,                    source, (int)args[1],                    destination, (int)args[3],                    args[4], args[5],                    args[6], args[7], (string)args[8]);            });            OP.Subscribe("System.HomeAll", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.HOME);            });            OP.Subscribe("System.Abort", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.ABORT);            });            OP.Subscribe("System.Reset", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.RESET);            });            OP.Subscribe("System.SetAutoMode", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.SetAutoMode);            });            OP.Subscribe("System.SetManualMode", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.SetManualMode);            });            OP.Subscribe("System.CreateJob", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.CreateJob, args[0]);            });            OP.Subscribe("System.StartJob", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.StartJob, args[0]);            });            OP.Subscribe("System.PauseJob", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.PauseJob, args[0]);            });            OP.Subscribe("System.ResumeJob", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.ResumeJob, args[0]);            });            OP.Subscribe("System.PauseAllJob", (cmd, args) => { return CheckToPostMessage((int)MSG.PauseAllJobs); }) ;            OP.Subscribe("System.ResumeAllJob", (cmd, args) => { return CheckToPostMessage((int)MSG.ResumeAllJobs); });            OP.Subscribe("System.StopJob", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.StopJob, args[0]);            });            OP.Subscribe("System.AbortJob", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.AbortJob, args[0]);            });            OP.Subscribe(RtOperation.SetConfig.ToString(), (name, args) =>            {                string sc_key = args[0] as string;                if (!string.IsNullOrWhiteSpace(sc_key) && args.Length > 1)                {                    SC.SetItemValue(sc_key, args[1]);                }                return true;            });            OP.Subscribe("System.ResetIdleCleanTime", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.ResetIdleCleanTime, args[0]);            });            OP.Subscribe("System.ResetIdlePurgeTime", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.ResetIdlePurgeTime, args[0]);            });            OP.Subscribe("System.SetWaferSize", (string cmd, object[] args) =>            {                string module = (string)args[0];                string size = (string)args[1];                switch (size)                {                    case "3":                        WaferManager.Instance.UpdateWaferSize(ModuleHelper.Converter(module), 0, WaferSize.WS3);                        break;                    case "4":                        WaferManager.Instance.UpdateWaferSize(ModuleHelper.Converter(module), 0, WaferSize.WS4);                        break;                    case "6":                        WaferManager.Instance.UpdateWaferSize(ModuleHelper.Converter(module), 0, WaferSize.WS6);                        break;                    default:                        EV.PostWarningLog("System", $"wafer size {size} not valid");                        break;                }                return true;            });            //OP.Subscribe("System.CassetteLeave", (string cmd, object[] args) =>            //{            //    return CheckToPostMessage((int)MSG.CassetteLeave);            //});            OP.Subscribe("System.Retry", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.Retry, args[0]);            });            OP.Subscribe("System.ConfirmComplete", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.ConfirmComplete, args[0]);            });            OP.Subscribe("WaferHolder.ResetLayoutWafers", (string cmd, object[] args) =>            {                return CheckToPostMessage((int)MSG.ResetWafers, args);            });        }        /// <summary>        /// 申请系统控制权        /// </summary>        /// <param name="cmd"></param>        /// <param name="args"></param>        /// <returns></returns>        private bool ApplySystemControl(string cmd, object[] args)        {            if (args[0].ToString() == "")            {                LOG.WriteLog(eEvent.WARN_ROUTER, "System", $"Current IP does not allow the application of UI control permissions");                return false;            }            string applyIp = args[0].ToString();            if (string.IsNullOrEmpty(_systemControlIp))            {                _systemControlIp = applyIp;                LOG.WriteLog(eEvent.EV_ROUTER, "System", $"{_systemControlIp} apply system control success");                return true;            }            else if(_systemControlIp!=applyIp)            {                LOG.WriteLog(eEvent.WARN_ROUTER, "System", $"{_systemControlIp} already has system control permission");                return false;            }            return false;        }        /// <summary>        /// 释放系统控制权        /// </summary>        /// <param name="cmd"></param>        /// <param name="args"></param>        /// <returns></returns>        private bool ReleaseSystemControl(string cmd, object[] args)        {            string releaseIp = args[0].ToString();            if (_systemControlIp == releaseIp)            {                LOG.WriteLog(eEvent.EV_ROUTER, "System", $"{releaseIp} release system control success");                _systemControlIp = "";            }            else            {                LOG.WriteLog(eEvent.ERR_ROUTER, "System", $"{releaseIp} is not SystemControlIp");            }            return false;        }        /// <summary>        /// 检验Secsgem在线情况        /// </summary>        /// <param name="controlState"></param>        /// <returns></returns>        private bool CheckSecsGemOnline(SecsGem.Core.EnumData.ControlState controlState)        {            if (controlState == SecsGem.Core.EnumData.ControlState.OnlineLocal || controlState == SecsGem.Core.EnumData.ControlState.OnlineRemote)            {                return true;            }            return false;        }        public bool CheckToPostMessage(int msg, params object[] args)        {            if (!fsm.FindTransition(fsm.State, msg))            {                LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"System is in {(RtState)fsm.State} state,can not do {(MSG)msg}");                return false;            }            Running = true;            fsm.PostMsg(msg, args);            return true;        }        private bool InvokeCreateWafer(string arg1, object[] args)        {            ModuleName chamber = ModuleHelper.Converter(args[0].ToString());            int slot = (int)args[1];            WaferStatus state = WaferStatus.Normal;            if (WaferManager.Instance.IsWaferSlotLocationValid(chamber, slot))            {                if (WaferManager.Instance.CheckHasWafer(chamber, slot))                {                    LOG.Write(eEvent.EV_ROUTER, "System", string.Format("{0} slot {1} already has wafer.create wafer is not valid", chamber, slot));                }                else if (WaferManager.Instance.CreateWafer(chamber, slot, state) != null)                {                    LOG.Write(eEvent.EV_WAFER_CREATE, ModuleName.System, chamber.ToString(), (slot + 1).ToString(), state.ToString());                }            }            else            {                LOG.Write(eEvent.WARN_ROUTER, "System", string.Format("Invalid position,{0},{1}", chamber.ToString(), slot.ToString()));                return false;            }            return true;        }        private bool InvokeDeleteWafer(string arg1, object[] args)        {            ModuleName chamber = ModuleHelper.Converter(args[0].ToString());            int slot = (int)args[1];            if (WaferManager.Instance.IsWaferSlotLocationValid(chamber, slot))            {                if (WaferManager.Instance.CheckHasWafer(chamber, slot))                {                    WaferManager.Instance.DeleteWafer(chamber, slot);                    EV.PostMessage(ModuleName.System.ToString(), EventEnum.WaferDelete, chamber.ToString(), slot + 1);                }                else                {                    LOG.Write(eEvent.EV_ROUTER, "System", string.Format("No wafer at {0} {1}, delete not valid", chamber.ToString(), slot + 1));                }            }            else            {                LOG.Write(eEvent.WARN_ROUTER, "System", string.Format("Invalid position,{0},{1}", chamber.ToString(), slot.ToString()));                return false;            }            return true;        }        private bool InvokeReturnWafer(string arg1, object[] args)        {            ModuleName target = ModuleHelper.Converter(args[0].ToString());            int slot = (int)args[1];            if (ModuleHelper.IsLoadPort(target))            {                LOG.Write(eEvent.WARN_ROUTER, "System", string.Format("Wafer already at LoadPort {0} {1}, return operation is not valid", target.ToString(), slot + 1));                return false;            }            if (!WaferManager.Instance.IsWaferSlotLocationValid(target, slot))            {                LOG.Write(eEvent.WARN_ROUTER, "System", string.Format("Invalid position,{0},{1}", target.ToString(), slot.ToString()));                return false;            }            WaferInfo wafer = WaferManager.Instance.GetWafer(target, slot);            if (wafer.IsEmpty)            {                LOG.Write(eEvent.WARN_ROUTER, "System", string.Format("No wafer at {0} {1}, return operation is not valid", target.ToString(), slot + 1));                return false;            }            return CheckToPostMessage((int)MSG.MoveWafer,                target, slot,                (ModuleName)wafer.OriginStation, wafer.OriginSlot,                false, 0, false, 0, "Blade1");                    }        protected override bool Init()        {            _jobCycle = new JobDispatcher();            Singleton<FaRemoteManager>.Instance.JobCycle = _jobCycle;            _homeAllRoutine = new ModuleHomeAllRoutine("System");                        BuildTransitionTable();            return true;        }               private void BuildTransitionTable()        {            //Init sequence            Transition(RtState.Init,            MSG.HOME,               FsmStartHome,               RtState.Initializing);            Transition(RtState.Idle,            MSG.HOME,               FsmStartHome,               RtState.Initializing);            Transition(RtState.Error,           MSG.HOME,               FsmStartHome,               RtState.Initializing);            EnterExitTransition<RtState, FSM_MSG>(RtState.AutoRunning,  FsmEnterAutoRunning,        FSM_MSG.NONE,       FsmExitAutoTransfer);            EnterExitTransition<RtState, FSM_MSG>(RtState.Transfer,     null,                       FSM_MSG.NONE,       FsmExitTransfer);            EnterExitTransition<RtState, FSM_MSG>(RtState.ReturnWafer,  null,                       FSM_MSG.NONE,       FsmExitReturnWafer);            AnyStateTransition(MSG.ERROR,       FsmError,               RtState.Error);            Transition(RtState.Idle,            FSM_MSG.TIMER,          FsmMonitor,                 RtState.Idle);            Transition(RtState.Init,            FSM_MSG.TIMER,          FsmMonitor,                 RtState.Init);            Transition(RtState.Init, MSG.ABORT, FsmAbort, RtState.Init);            Transition(RtState.Error, MSG.ABORT, FsmAbort, RtState.Init);            Transition(RtState.Idle, MSG.ABORT, FsmAbort, RtState.Idle);            Transition(RtState.Initializing, MSG.ABORT, FsmAbort, RtState.Init);            Transition(RtState.Initializing,    FSM_MSG.TIMER,          FsmMonitorHome,             RtState.Idle);            Transition(RtState.Initializing,    MSG.ERROR,              FsmError,                   RtState.Error);            //Auto/manual             Transition(RtState.Idle,            MSG.SetAutoMode,        FsmStartAutoTransfer,       RtState.AutoIdle);            Transition(RtState.AutoAborting, FSM_MSG.TIMER, FsmAutoTransfer, RtState.AutoIdle);            Transition(RtState.AutoRunning,     FSM_MSG.TIMER,          FsmAutoTransfer,            RtState.AutoIdle);            Transition(RtState.AutoRunning, MSG.ABORT, FsmAbort, RtState.AutoAborting);            Transition(RtState.AutoAborting, MSG.SetManualMode, FsmStartAbortingSetManualMode, RtState.Idle);            //Transition(RtState.AutoRunning,   MSG.SetManualMode,      FsmStartSetManualMode,      RtState.Idle);            Transition(RtState.AutoRunning,     MSG.JobDone,            FsmJobDone,                 RtState.AutoIdle);            //Transition(RtState.AutoRunning,   MSG.CassetteLeave,      fCassetteLeave,             RtState.AutoRunning);   //For unload light control off afer job done            Transition(RtState.AutoRunning,     MSG.CreateJob,          FsmCreateJob,               RtState.AutoRunning);            Transition(RtState.AutoRunning,     MSG.StartJob,           FsmStartJob,                RtState.AutoRunning);            Transition(RtState.AutoRunning,     MSG.PauseJob,           FsmPauseJob,                RtState.AutoRunning);            Transition(RtState.AutoRunning,     MSG.PauseAllJobs,       FsmPauseAllJobs,            RtState.AutoRunning);            Transition(RtState.AutoRunning,     MSG.ResumeJob,          FsmResumeJob,               RtState.AutoRunning);            Transition(RtState.AutoRunning,     MSG.ResumeAllJobs,      FsmResumeAllJobs,           RtState.AutoRunning);            Transition(RtState.AutoRunning,     MSG.StopJob,            FsmStopJob,                 RtState.AutoRunning);            Transition(RtState.AutoRunning,     MSG.Retry,              FsmRetry,                   RtState.AutoRunning);            Transition(RtState.AutoRunning,     MSG.ConfirmComplete,    FsmConfirmComplete,         RtState.AutoRunning);            Transition(RtState.AutoIdle,        FSM_MSG.TIMER,          FsmMonitorAutoIdle,         RtState.AutoIdle);            Transition(RtState.AutoIdle,        MSG.SetManualMode,      FsmStartSetManualMode,      RtState.Idle);            Transition(RtState.AutoIdle,        MSG.CreateJob,          FsmCreateJob,               RtState.AutoIdle);            Transition(RtState.AutoIdle,        MSG.StartJob,           FsmStartJob,                RtState.AutoRunning);            Transition(RtState.AutoIdle,        MSG.PauseJob,           FsmPauseJob,                RtState.AutoIdle);            Transition(RtState.AutoIdle,        MSG.PauseAllJobs,       FsmPauseAllJobs,            RtState.AutoIdle);            Transition(RtState.AutoIdle,        MSG.ResumeJob,          FsmResumeJob,               RtState.AutoIdle);            Transition(RtState.AutoIdle,        MSG.ResumeAllJobs,      FsmResumeAllJobs,           RtState.AutoIdle);            Transition(RtState.AutoIdle,        MSG.StopJob,            FsmStopJob,                 RtState.AutoIdle);            Transition(RtState.AutoIdle,        MSG.FaStartJob,         FsmEnterAutoRunning,        RtState.AutoRunning);            Transition(RtState.AutoRunning,     MSG.FaStartJob,         FsmEnterAutoRunning,        RtState.AutoRunning);            Transition(RtState.AutoIdle, MSG.ResetWafers, ResetWafers, RtState.AutoIdle);            Transition(RtState.Idle, MSG.ResetWafers, ResetWafers, RtState.Idle);            Transition(RtState.Init, MSG.ResetWafers, ResetWafers, RtState.Init);        }        private bool FsmMonitor(object[] objs)        {            return true;        }        /// <summary>        /// 检验前置条件        /// </summary>        /// <returns></returns>        private bool CheckPreCondition()        {            if (ModuleHelper.IsInstalled(ModuleName.PUF1))            {                PufVacuum pufVacuum = DEVICE.GetDevice<PufVacuum>($"{ModuleName.PUF1}.Vacuum");                if (!pufVacuum.IsChuckAReleased || !pufVacuum.ISChuckBReleased)                {                    LOG.WriteLog(eEvent.ERR_AXIS, ModuleName.PUF1.ToString(), "Vacuum is on");                    return false;                }            }            if (ModuleHelper.IsInstalled(ModuleName.Loader1))            {                LoaderSideDevice loaderSideADevice = DEVICE.GetDevice<LoaderSideDevice>($"{ModuleName.Loader1}.SideA");                LoaderSideDevice loaderSideBDevice = DEVICE.GetDevice<LoaderSideDevice>($"{ModuleName.Loader1}.SideB");                if (loaderSideADevice.SideData.CRSVacuum || loaderSideBDevice.SideData.CRSVacuum)                {                    LOG.WriteLog(eEvent.ERR_AXIS, ModuleName.Loader1.ToString(), "Vacuum is on");                    return false;                }            }            if (ModuleHelper.IsInstalled(ModuleName.SRD1))            {                SrdCommonDevice srdCommonDevice = DEVICE.GetDevice<SrdCommonDevice>($"{ModuleName.SRD1}.Common");                if (!srdCommonDevice.CommonData.ChuckVacuum)                {                    LOG.WriteLog(eEvent.ERR_AXIS, ModuleName.SRD1.ToString(), "Vacuum is on");                    return false;                }            }            if (ModuleHelper.IsInstalled(ModuleName.SRD2))            {                SrdCommonDevice srdCommonDevice = DEVICE.GetDevice<SrdCommonDevice>($"{ModuleName.SRD2}.Common");                if (!srdCommonDevice.CommonData.ChuckVacuum)                {                    LOG.WriteLog(eEvent.ERR_AXIS, ModuleName.SRD2.ToString(), "Vacuum is on");                    return false;                }            }            return true;        }        private bool FsmStartHome(object[] objs)        {            if (!CheckPreCondition())            {                return false;            }            List<string> keys = _moduleEntitiesDic.Keys.ToList();            foreach (string item in keys)            {                if (!NeedSequenceHome(item))                {                    IModuleEntity entity = _moduleEntitiesDic[item];                    if (!entity.IsDisable)                    {                        entity.Invoke("HomeAll");                    }                }            }            _homeAllRoutine.Start();            _reservoirMetalRoutines.Clear();            foreach (string item in keys)            {                if (Enum.TryParse(item, out ModuleName moduleName))                {                    if (ModuleHelper.IsReservoir(moduleName))                    {                        IModuleEntity moduleEntity = _moduleEntitiesDic[item];                        if (!moduleEntity.IsDisable)                        {                            ReservoirMetalHomeRoutine reservoirMetalHomeRoutine = new ReservoirMetalHomeRoutine(item);                            _reservoirMetalRoutines.Add(reservoirMetalHomeRoutine);                        }                    }                }            }            foreach (ReservoirMetalHomeRoutine item in _reservoirMetalRoutines)            {                item.Start();            }            _homeStopWatch.Restart();            _jobCycle.RemoveAllJob();            return true;        }        /// <summary>        /// 需要按照顺序Home        /// </summary>        /// <returns></returns>        private bool NeedSequenceHome(string item)        {            bool result = item == ModuleName.PUF1.ToString()  || item == ModuleName.Loader1.ToString() ||                item == ModuleName.Transporter2.ToString() || item == ModuleName.Transporter1.ToString();            if (result)            {                return true;            }            else            {                if(Enum.TryParse(item,out ModuleName moduleName))                {                    if (!ModuleHelper.IsMetal(moduleName)&&!ModuleHelper.IsReservoir(moduleName))                    {                        return false;                    }                }                return true;            }        }        private bool FsmMonitorHome(object[] objs)        {            RState rstate = _homeAllRoutine.Monitor();            if (_homeStopWatch.ElapsedMilliseconds <= 500)            {                return false;            }            if (rstate == RState.Failed || rstate == RState.Timeout)            {                PostMsg(MSG.ERROR);                return false;            }            List<string> keys = LoadInitializeCheckModuleList();            int idleCount = 0;            foreach (string item in keys)            {                IModuleEntity ModuleEntity = _moduleEntitiesDic[item];                if (ModuleEntity.IsError && !NeedSequenceHome(item))                {                    LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"{ModuleEntity.Module} home error");                    PostMsg(MSG.ERROR);                    return true;                }                else if (ModuleEntity.IsIdle)                {                    idleCount++;                }            }            int homeCount = 0;            foreach (ReservoirMetalHomeRoutine item in _reservoirMetalRoutines)            {                RState ret = item.Monitor();                if (ret != RState.Running)                {                    homeCount++;                }            }            if (homeCount != _reservoirMetalRoutines.Count)            {                return false;            }            if (idleCount == keys.Count)            {                return true;            }            else            {                return false;            }        }        /// <summary>        /// 加载初始化检验模块集合        /// </summary>        /// <returns></returns>        private List<string> LoadInitializeCheckModuleList()        {            string checkModuleList = SC.GetStringValue("System.InitializeCheckModuleList");            List<string> moduleList= checkModuleList.Split(',').ToList();            List<string> modules = new List<string>();            foreach (var item in moduleList)            {                if(Enum.TryParse(item, out ModuleName moduleName))                {                    if (ModuleHelper.IsInstalled(moduleName))                     {                        modules.Add(item);                    }                }             }            return modules;        }        private bool FsmEnterAutoRunning(object[] objs)        {            return true;        }        private bool FsmExitAutoTransfer(object[] objs)        {            _jobCycle.Clear();            return true;        }        private bool FsmExitTransfer(object[] objs)        {            return true;        }        private bool FsmExitReturnWafer(object[] objs)        {            return true;        }        private bool FsmError(object[] objs)        {            return true;        }        private bool FsmAbort(object[] objs)        {            //_manualTransfer.Clear();            //_returnWafer.Clear();            //_jobCycle.Clear();            AlarmListManager.Instance.ClearAllAlarm();            return _jobCycle.SystemAbort();        }        private bool FsmStartAutoTransfer(object[] objs)        {            return _jobCycle.Start(objs) == RState.Running;        }        private bool FsmAutoTransfer(object[] objs)        {            if (_jobCycle.CheckJobJustDone(out string jobInfo))            {                //EV.PostPopDialogMessage(EventLevel.InformationNoDelay, "Job complete", jobInfo);                LOG.Write(eEvent.EV_ROUTER, ModuleName.System, $"Job complete,{jobInfo}");            }            if (_jobCycle.CheckAllJobDone())            {                if (!CheckToPostMessage((int)MSG.JobDone))                    return false;            }            RState ret = _jobCycle.Monitor();            if (ret == RState.Failed)            {                if (!CheckToPostMessage((int)MSG.ERROR))                    return false;            }            return ret == RState.End;        }        private bool FsmAbortAutoTransfer(object[] objs)        {            _jobCycle.Clear();            return true;        }        private bool FsmJobDone(object[] objs)        {            return true;        }        private bool FsmCreateJob(object[] objs)        {            return _jobCycle.CreateJob((Dictionary<string, object>)objs[0],out string reason);        }        private bool FsmStartJob(object[] objs)        {            bool result = CheckPMCounter();            if (!result)            {                return false;            }            return _jobCycle.StartJob((string)objs[0],out string reason);        }        /// <summary>        /// 检查PM counter        /// </summary>        /// <returns></returns>        private bool CheckPMCounter()        {            bool result = false;            foreach (string item in ReservoirItemManager.Instance.InstalledModules)            {                result = ReservoirUsageMonitor(item);                if (!result)                {                    return false;                }            }            foreach (string item in MetalItemManager.Instance.InstalledModules)            {                result = MetalUsageMointor(item);                if (!result)                {                    return false;                }            }            return true;        }        private bool FsmPauseJob(object[] objs)        {            return _jobCycle.PauseJob((string)objs[0],out string reason);        }        private bool FsmResumeJob(object[] objs)        {            return _jobCycle.ResumeJob((string)objs[0],out string reason);        }        private bool FsmPauseAllJobs(object[] objs)        {            return _jobCycle.PauseAllJobs();        }        private bool FsmResumeAllJobs(object[] objs)        {            return _jobCycle.ResumeAllJobs();        }        private bool FsmStopJob(object[] objs)        {            return _jobCycle.StopJob((string)objs[0], out string reason);        }        /// <summary>        /// 重试        /// </summary>        /// <param name="objs"></param>        /// <returns></returns>        private bool FsmRetry(object[] objs)        {            string moduleName = objs[0].ToString();            IModuleEntity moduleEntity = GetModule<IModuleEntity>(moduleName);            moduleEntity.Invoke("Retry");            return true;        }        /// <summary>        /// 重试        /// </summary>        /// <param name="objs"></param>        /// <returns></returns>        private bool FsmConfirmComplete(object[] objs)        {            string moduleName = objs[0].ToString();            IModuleEntity moduleEntity = GetModule<IModuleEntity>(moduleName);            moduleEntity.Invoke("ConfirmComplete");            return true;        }        private bool FsmMonitorAutoIdle(object[] objs)        {            RState ret = _jobCycle.Monitor();            return ret == RState.End;        }        private bool FsmStartAbortingSetManualMode(object[] objs)        {            return _jobCycle.RemoveAllJob();        }        private bool FsmStartSetManualMode(object[] objs)        {            if (_jobCycle.HasJobRunning)            {                LOG.Write(eEvent.WARN_ROUTER, "System", "Can not change to manual mode, abort running job first");                return false;            }            return true;        }        /// <summary>        /// 重置Wafers        /// </summary>        /// <param name="objs"></param>        /// <returns></returns>        private bool ResetWafers(object[] objs)        {            return WaferHolderManager.Instance.ResetLayoutWafers();        }        /// <summary>        /// 获取模块对象        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="name"></param>        /// <returns></returns>        public T GetModule<T>(string name) where T : class, IModuleEntity        {            return _moduleEntitiesDic.ContainsKey(name)?_moduleEntitiesDic[name] as T:default(T);        }        /// <summary>        /// 根据模块类型获取模块集合        /// </summary>        /// <param name="type"></param>        /// <returns></returns>        public List<IModuleEntity> GetModulesByModuleType(ModuleType type)        {            return _modultTypeEntitiesDic.ContainsKey(type) ? _modultTypeEntitiesDic[type] : new List<IModuleEntity>();        }        /// <summary>        /// 监控PM Counter Reservoir Usage        /// </summary>        public bool ReservoirUsageMonitor(string Module)        {            ReservoirUsage reservoirUsage = ReservoirUsageManager.Instance.GetReservoirUsage(Module);            ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);            if (reservoirUsage == null || reservoirEntity == null) return true;            //reservoirTotalAmpHours Check            double reservoirTotalAmpHoursWarningLimit = 0;            if (SC.ContainsItem($"Reservoir.{Module}.ReservoirTotalAmpHoursWarningLimit"))            {                reservoirTotalAmpHoursWarningLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.ReservoirTotalAmpHoursWarningLimit");            }            double reservoirTotalAmpHoursFaultLimit = 0;            if (SC.ContainsItem($"Reservoir.{Module}.ReservoirTotalAmpHoursFaultLimit"))            {                reservoirTotalAmpHoursFaultLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.ReservoirTotalAmpHoursFaultLimit");            }            if (reservoirUsage.TotalUsage > reservoirTotalAmpHoursFaultLimit && reservoirTotalAmpHoursFaultLimit != 0)            {                LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Total Usage(AHr):{reservoirUsage.TotalUsage} is over config item ReservoirTotalAmpHoursFaultLimit:{reservoirTotalAmpHoursFaultLimit}");                return false;            }            else if (reservoirUsage.TotalUsage > reservoirTotalAmpHoursWarningLimit && reservoirTotalAmpHoursWarningLimit != 0)            {                LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Total Usage(AHr):{reservoirUsage.TotalUsage} is over config item ReservoirTotalAmpHoursWarningLimit:{reservoirTotalAmpHoursWarningLimit}");            }            //MembraneTotalAmpHoursCheck            double membraneTotalAmpHoursWarningLimit = 0;            if (SC.ContainsItem($"Reservoir.{Module}.MembraneTotalAmpHoursWarningLimit"))            {                membraneTotalAmpHoursWarningLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.MembraneTotalAmpHoursWarningLimit");            }            double membraneTotalAmpHoursFaultLimit = 0;            if (SC.ContainsItem($"Reservoir.{Module}.MembraneTotalAmpHoursFaultLimit"))            {                membraneTotalAmpHoursFaultLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.MembraneTotalAmpHoursFaultLimit");            }            if (reservoirUsage.MembranceUsage > membraneTotalAmpHoursFaultLimit && membraneTotalAmpHoursFaultLimit != 0)            {                LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Membrane Usage(AHr):{reservoirUsage.MembranceUsage} is over config item MembraneTotalAmpHoursFaultLimit:{membraneTotalAmpHoursFaultLimit}");                return false;            }            else if (reservoirUsage.MembranceUsage > membraneTotalAmpHoursWarningLimit && membraneTotalAmpHoursWarningLimit != 0)            {                LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Membrane Usage(AHr):{reservoirUsage.MembranceUsage} is over config item MembraneTotalAmpHoursWarningLimit:{membraneTotalAmpHoursWarningLimit}");            }            double bathTotalAmpHoursWarningLimit = 0;            if (SC.ContainsItem($"Reservoir.{Module}.BathTotalAmpHoursWarningLimit"))            {                bathTotalAmpHoursWarningLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.BathTotalAmpHoursWarningLimit");            }            double bathTotalAmpHoursFaultLimit = 0;            if (SC.ContainsItem($"Reservoir.{Module}.BathTotalAmpHoursFaultLimit"))            {                bathTotalAmpHoursFaultLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.BathTotalAmpHoursFaultLimit");            }            if (reservoirUsage.BathUsage > bathTotalAmpHoursFaultLimit && bathTotalAmpHoursFaultLimit != 0)            {                LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Bath Usage(AHr):{reservoirUsage.BathUsage} is over config item BathTotalAmpHoursFaultLimit:{bathTotalAmpHoursFaultLimit}");                return false;            }            else if (reservoirUsage.BathUsage > bathTotalAmpHoursWarningLimit && bathTotalAmpHoursWarningLimit != 0)            {                LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Bath Usage(AHr):{reservoirUsage.BathUsage} is over config item BathTotalAmpHoursWarningLimit:{bathTotalAmpHoursWarningLimit}");            }            //BathTotalDaysCheck            int bathTotalDaysWarningLimit = 0;            if (SC.ContainsItem($"Reservoir.{Module}.BathTotalDaysWarningLimit"))            {                bathTotalDaysWarningLimit = SC.GetValue<int>($"Reservoir.{Module}.BathTotalDaysWarningLimit");            }            int bathTotalDaysFaultLimit = 0;            if (SC.ContainsItem($"Reservoir.{Module}.BathTotalDaysFaultLimit"))            {                bathTotalDaysFaultLimit = SC.GetValue<int>($"Reservoir.{Module}.BathTotalDaysFaultLimit");            }            if (reservoirUsage.BathUsageDays > bathTotalDaysFaultLimit && bathTotalDaysFaultLimit != 0)            {                LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Bath Usage(Days):{reservoirUsage.BathUsageDays} is over config item BathTotalDaysFaultLimit:{bathTotalDaysFaultLimit}");                return false;            }            else if (reservoirUsage.BathUsageDays > bathTotalDaysWarningLimit && bathTotalDaysWarningLimit != 0)            {                LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Bath Usage(Days):{reservoirUsage.BathUsageDays} is over config item BathTotalDaysWarningLimit:{bathTotalDaysWarningLimit}");            }            //ReservoirTotalWafersCheck            int reservoirTotalWafersWarningLimit = 0;            if (SC.ContainsItem($"Reservoir.{Module}.ReservoirTotalWafersWarningLimit"))            {                reservoirTotalWafersWarningLimit = SC.GetValue<int>($"Reservoir.{Module}.ReservoirTotalWafersWarningLimit");            }            int reservoirTotalWafersFaultLimit = 0;            if (SC.ContainsItem($"Reservoir.{Module}.ReservoirTotalWafersFaultLimit"))            {                reservoirTotalWafersFaultLimit = SC.GetValue<int>($"Reservoir.{Module}.ReservoirTotalWafersFaultLimit");            }            if (reservoirUsage.TotalWafers > reservoirTotalWafersFaultLimit && reservoirTotalWafersFaultLimit != 0)            {                LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Total Wafers:{reservoirUsage.TotalWafers} is over config item ReservoirTotalWafersFaultLimit:{reservoirTotalWafersFaultLimit}");                return false;            }            else if (reservoirUsage.TotalWafers > reservoirTotalWafersWarningLimit && reservoirTotalWafersWarningLimit != 0)            {                LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Total Wafers:{reservoirUsage.TotalWafers} is over config item ReservoirTotalWafersWarningLimit:{reservoirTotalWafersWarningLimit}");            }            //CMMAnodeTotalAmpHoursCheck            double cmmAnodeTotalAmpHoursWarningLimit = 0;            if (SC.ContainsItem($"Reservoir.{Module}.CMMAnodeTotalAmpHoursWarningLimit"))            {                cmmAnodeTotalAmpHoursWarningLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.CMMAnodeTotalAmpHoursWarningLimit");            }            double cmmAnodeTotalAmpHoursFaultLimit = 0;            if (SC.ContainsItem($"Reservoir.{Module}.CMMAnodeTotalAmpHoursFaultLimit"))            {                cmmAnodeTotalAmpHoursFaultLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.CMMAnodeTotalAmpHoursFaultLimit");            }            if (reservoirUsage.CMMAnodeUsage > cmmAnodeTotalAmpHoursFaultLimit && cmmAnodeTotalAmpHoursFaultLimit != 0)            {                LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} CMM Anode Usage(AHr):{reservoirUsage.CMMAnodeUsage} is over config item CMMAnodeTotalAmpHoursFaultLimit:{cmmAnodeTotalAmpHoursFaultLimit}");                return false;            }            else if (reservoirUsage.CMMAnodeUsage > cmmAnodeTotalAmpHoursWarningLimit && cmmAnodeTotalAmpHoursWarningLimit != 0)            {                LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} CMM Anode Usage(AHr):{reservoirUsage.CMMAnodeUsage} is over config item CMMAnodeTotalAmpHoursWarningLimit:{cmmAnodeTotalAmpHoursWarningLimit}");            }            //CMMCathodeTotalAmpHoursCheck            double cmmCathodeTotalAmpHoursWarningLimit = 0;            if (SC.ContainsItem($"Reservoir.{Module}.CMMCathodeTotalAmpHoursWarningLimit"))            {                cmmCathodeTotalAmpHoursWarningLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.CMMCathodeTotalAmpHoursWarningLimit");            }            double cmmCathodeTotalAmpHoursFaultLimit = 0;            if (SC.ContainsItem($"Reservoir.{Module}.CMMCathodeTotalAmpHoursFaultLimit"))            {                cmmCathodeTotalAmpHoursFaultLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.CMMCathodeTotalAmpHoursFaultLimit");            }            if (reservoirUsage.CMMMembranceUsage > cmmCathodeTotalAmpHoursFaultLimit && cmmCathodeTotalAmpHoursFaultLimit != 0)            {                LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} CMM Cathode Usage(AHr):{reservoirUsage.CMMMembranceUsage} is over config item CMMCathodeTotalAmpHoursFaultLimit:{cmmCathodeTotalAmpHoursFaultLimit}");                return false;            }            else if (reservoirUsage.CMMMembranceUsage > cmmCathodeTotalAmpHoursWarningLimit && cmmCathodeTotalAmpHoursWarningLimit != 0)            {                LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} CMM Cathode Usage(AHr):{reservoirUsage.CMMMembranceUsage} is over config item CMMCathodeTotalAmpHoursWarningLimit:{cmmCathodeTotalAmpHoursWarningLimit}");            }            return true;        }        /// <summary>        /// 监控 PM Counter Metal用量        /// </summary>        private bool MetalUsageMointor(string Module)        {            MetalUsage metalUsage = MetalUsageManager.Instance.GetMetalUsage(Module);            if (metalUsage != null)            {                //TotalAUsage                if (metalUsage.TotalUsage > SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit") != 0)                {                    if (metalUsage.TotalUsage > SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit"))                    {                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit")}");                        return false;                    }                    else                    {                        LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit")}");                    }                }                //AnodeAUsage                if (metalUsage.AnodeAUsage > SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit") != 0)                {                    if (metalUsage.AnodeAUsage > SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit"))                    {                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit")}");                        return false;                    }                    else                    {                        LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit")}");                    }                }                //AnodeBUsage                if (metalUsage.AnodeBUsage > SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit") != 0)                {                    if (metalUsage.AnodeBUsage > SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit"))                    {                        LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit")}");                        return false ;                    }                    else                    {                        LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit")}");                    }                }                //MembraneAUsage                if (metalUsage.MembranceAUsage > SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit") != 0)                {                    if (metalUsage.MembranceAUsage > SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit"))                    {                        LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit")}");                        return false;                    }                    else                    {                        LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit")}");                    }                }                //MembraneBUsage                if (metalUsage.MembranceBUsage > SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit") != 0)                {                    if (metalUsage.MembranceBUsage > SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit"))                    {                        LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit")}");                    }                    else                    {                        LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit")}");                    }                }                //TotalWafer                if (metalUsage.TotalWafers > SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit") && SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit") != 0)                {                    if (metalUsage.TotalWafers > SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit"))                    {                        LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit")}");                        return false;                    }                    else                    {                        LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit")}");                    }                }                //AnodeAWafer                if (metalUsage.AnodeAWafers > SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit") != 0)                {                    if (metalUsage.AnodeAWafers > SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit"))                    {                        LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit")}");                        return false;                    }                    else                    {                        LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit")}");                    }                }                //AnodeBWafer                if (metalUsage.AnodeBWafers > SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit") != 0)                {                    if (metalUsage.AnodeBWafers > SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit"))                    {                        LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit")}");                        return false;                    }                    else                    {                        LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit")}");                    }                }                //AnodeAbathUsage                if (metalUsage.AnodeABathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit") != 0)                {                    if (metalUsage.AnodeABathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit"))                    {                        LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit")}");                        return false;                    }                    else                    {                        LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit")}");                    }                }                //AnodeBbathUsage                if (metalUsage.AnodeBBathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit") != 0)                {                    if (metalUsage.AnodeBBathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit"))                    {                        LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit")}");                        return false;                    }                    else                    {                        LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit")}");                    }                }            }            return true;        }    }}
 |