Browse Source

1.增加Fa模块事件上报相关接口FaEvet,与recipejob,loadportjob事件上报接口

Intern01 1 year ago
parent
commit
c8473cb60c

+ 267 - 0
Venus/Venus_RT/FAs/FaEvent.cs

@@ -0,0 +1,267 @@
+using Aitex.Controls.RecipeCompare;
+using Aitex.Core.Common;
+using Aitex.Core.RT.Event;
+using Aitex.Core.RT.Log;
+using Aitex.Core.RT.OperationCenter;
+using Aitex.Core.Util;
+using FabConnect.SecsGemInterface.Common.ToolModel;
+using log4net.Core;
+using MECF.Framework.Common.Equipment;
+using MECF.Framework.Common.SubstrateTrackings;
+using Mono.Security.Authenticode;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.Serialization;
+using System.Text;
+using System.Threading.Tasks;
+using Venus_RT.HostWrapper;
+using static Aitex.Core.RT.Log.LOG;
+using static Mono.Security.X509.X520;
+
+namespace Venus_RT.FAs
+{
+    public class FaEvent
+    {
+        //public event Action<PostFAItem> PostEvent;
+        static Dictionary<string, PostFAItem> _eventDic = new Dictionary<string, PostFAItem>();
+        static FixSizeQueue<PostFAItem> _eventQueue;
+        PeriodicJob _eventJob;
+        private const string INFORMATION_EVENT = "INFORMATION_EVENT";
+        private const string WARNING_EVENT = "WARNING_EVENT";
+        private const string ALARM_EVENT = "ALARM_EVENT";
+
+
+        public void Initialize(string commonEventListXmlFile)
+        {
+            _eventJob = new PeriodicJob(100, this.PeriodicRun, "FaEventPeriodicJob", true);
+            _eventQueue = new FixSizeQueue<PostFAItem>(1000);
+            AddFaEvent(new PostFAItem(INFORMATION_EVENT, EventLevel.Information));
+            AddFaEvent(new PostFAItem(WARNING_EVENT, EventLevel.Warning));
+            AddFaEvent(new PostFAItem(ALARM_EVENT, EventLevel.Alarm));
+            try
+            {
+                EventDefine eventList = CustomXmlSerializer.Deserialize<EventDefine>(new FileInfo(commonEventListXmlFile));
+
+                foreach (var item in eventList.Items)
+                {
+                    _eventDic[item.EventEnum] = new PostFAItem();
+                    _eventDic[item.EventEnum].FaEventEnum = item.EventEnum;
+                    _eventDic[item.EventEnum].Description = item.Description;
+                    _eventDic[item.EventEnum].Level = item.Level;
+                    _eventDic[item.EventEnum].Source = item.Source;
+                    _eventDic[item.EventEnum].FaEventEnum = item.EventEnum;
+                }
+            }
+            catch (ArgumentNullException)
+            {
+                throw new ApplicationException("初始化EventManager没有设置Event列表文件");
+            }
+            catch (FileNotFoundException ex)
+            {
+                throw new ApplicationException("没有找到Event列表文件," + ex.Message);
+            }
+            catch (Exception ex)
+            {
+                throw new ApplicationException("EventDefine文件格式不对," + commonEventListXmlFile + ",\r\n" + ex.Message);
+            }
+        }
+        public void Terminate()
+        {
+            if (_eventJob != null)
+            {
+                _eventJob.Stop();
+                _eventJob = null;
+            }
+        }
+
+        public static void AddFaEvent(PostFAItem item)
+        {
+            if (_eventDic.ContainsKey(item.FaEventEnum))
+            {
+                return;
+            }
+
+            _eventDic[item.FaEventEnum] = item;
+        }
+        bool PeriodicRun()
+        {
+            PostFAItem FaEv;
+            while (_eventQueue.TryDequeue(out FaEv))
+            {
+                try
+                {
+                    InstanceOnOnEvent(FaEv);
+                }
+                catch (Exception ex)
+                {
+
+                }
+            }
+            return true;
+        }
+        private void InstanceOnOnEvent(PostFAItem obj)
+        {
+            if (obj.Level != EventLevel.Alarm)
+            {
+                Singleton<FaManager>.Instance.NotifyEvent(obj.FaEventEnum, obj.DVID, obj.ObjDVID);
+            }
+            else
+            {
+                Singleton<FaManager>.Instance.NotifyAlarm(obj.FaEventEnum, obj.DVID, obj.ObjDVID, obj.Description);
+            }
+        }
+        public static void SendHost(string module, string eventName, params object[] args)
+        {
+            if (!_eventDic.ContainsKey(eventName))
+            {
+                //LOG.Write(eEvent.INFO_FA, "Event name not registered, " + eventName);
+                return;
+            }
+            PostFAItem item = _eventDic[eventName].Clone();
+            item.Source = module;
+            item.Description = string.Format(_eventDic[eventName].Description, args);
+            if (!string.IsNullOrWhiteSpace(item.Source))
+            {
+                item.Description = item.Source + "  " + item.Description;
+            }
+            _eventQueue.Enqueue(item);
+        }
+        public static void SendHost(string module, string eventName, string description)
+        {
+            if (!_eventDic.ContainsKey(eventName))
+            {
+                //LOG.Write(eEvent.INFO_FA, "Event name not registered, " + eventName);
+                return;
+            }
+            PostFAItem item = _eventDic[eventName].Clone();
+            item.Source = module;
+            item.Description = description;
+            if (!string.IsNullOrWhiteSpace(item.Source))
+            {
+                item.Description = item.Source + "  " + item.Description;
+            }
+            _eventQueue.Enqueue(item);
+        }
+
+        public static void SendHost(string eventName, SerializableDictionary<string, string> dvid)
+        {
+            if (!_eventDic.ContainsKey(eventName))
+            {
+                return;
+            }
+            PostFAItem item = _eventDic[eventName].Clone();
+
+            item.Description = string.Format(_eventDic[eventName].Description);
+            item.DVID = dvid;
+            item.Source = _eventDic[eventName].Source;
+            _eventQueue.Enqueue(item);
+        }
+        public static void SendHost(string eventName, SerializableDictionary<string, object> dvid)
+        {
+            if (!_eventDic.ContainsKey(eventName))
+            {
+                return;
+            }
+            PostFAItem item = _eventDic[eventName].Clone(dvid);
+            item.Description = string.Format(_eventDic[eventName].Description);
+            item.ObjDVID = dvid;
+            item.Source = _eventDic[eventName].Source;
+            _eventQueue.Enqueue(item);
+        }
+        public static void FaPostAlarm(string module, string message)
+        {
+            SendHost(module, WARNING_EVENT, message);
+        }
+        public static void FaPostWarning(string module, string message)
+        {
+            SendHost(module, ALARM_EVENT, message);
+        }
+        public static void FaPostInfo(string module, string message)
+        {
+            SendHost(module, INFORMATION_EVENT, message);
+        }
+        public static void FaPostMessage(string module, string message, params object[] args)
+        {
+            SendHost(module, message,args);
+        }
+        public static void FaNotify(string eventName, SerializableDictionary<string, string> dvid)
+        {
+            SendHost(eventName, dvid);
+        }
+        public static void FaNotify(string eventName, SerializableDictionary<string, object> dvid)
+        {
+            SendHost(eventName, dvid);
+        }
+    }
+
+    public class PostFAItem
+    {
+        public string Source { get; set; }
+        public string FaEventEnum { get; set; }
+        public int Id { get; set; }
+        public string Explaination { get; set; }
+        public EventLevel Level { get; set; }
+        public string Description { get; set; }
+        public SerializableDictionary<string, string> DVID
+        {
+            get;
+            set;
+        }
+        public SerializableDictionary<string, object> ObjDVID
+        {
+            get;
+            set;
+        }
+        public PostFAItem Clone()
+        {
+            PostFAItem result = new PostFAItem();
+            result.Description = Description;
+            result.FaEventEnum = FaEventEnum;
+            result.Explaination = Explaination;
+            result.Id = Id;
+            result.Level = Level;
+            result.Source = Source;
+            result.DVID = DVID;
+            result.ObjDVID = ObjDVID;
+            return result;
+        }
+        public PostFAItem Clone(SerializableDictionary<string, object> objDvid)
+        {
+            PostFAItem result = new PostFAItem();
+            result.Description = Description;
+            result.FaEventEnum = FaEventEnum;
+            result.Explaination = Explaination;
+            result.Id = Id;
+            result.Level = Level;
+            result.Source = Source;
+            result.DVID = DVID;
+            result.ObjDVID = objDvid;
+            return result;
+        }
+        public PostFAItem()
+        {
+
+        }
+        public PostFAItem(string name, EventLevel level)
+        {
+            FaEventEnum = name;
+            Level = level;
+        }
+        public PostFAItem(string source, string name, string description, EventLevel level)
+        {
+            Source = source;
+            FaEventEnum = name;
+            Description = description;
+            Level = level;
+        }
+        public PostFAItem(string source, string name, string description)
+        {
+            Source = source;
+            FaEventEnum = name;
+            Description = description;
+        }
+    }
+
+}

+ 19 - 4
Venus/Venus_RT/FAs/FaManager.cs

@@ -72,10 +72,25 @@ namespace Venus_RT.HostWrapper
 
         public string GetSvidValue(string svName)
         {
-            if (svName == "PMA.RecipeProcessTime")
-                svName = "PMA.RecipeTotalElapsedSeconds";
-            else if (svName == "PMB.RecipeProcessTime")
-                svName = "PMB.RecipeTotalElapsedSeconds";
+            switch (svName)
+            {
+                case "PMA.RecipeProcessTime":
+                    svName = "PMA.RecipeTotalElapsedSeconds";
+                    break;
+                case "PMB.RecipeProcessTime":
+                    svName = "PMB.RecipeTotalElapsedSeconds";
+                    break;
+                case "PMC.RecipeProcessTime":
+                    svName = "PMC.RecipeTotalElapsedSeconds";
+                    break;
+                case "PMD.RecipeProcessTime":
+                    svName = "PMD.RecipeTotalElapsedSeconds";
+                    break;
+            }
+            //if (svName == "PMA.RecipeProcessTime")
+            //    svName = "PMA.RecipeTotalElapsedSeconds";
+            //else if (svName == "PMB.RecipeProcessTime")
+            //    svName = "PMB.RecipeTotalElapsedSeconds";
 
             object data = DATA.Poll(svName);
             if (data != null)

+ 4 - 0
Venus/Venus_RT/Instances/ToolLoader.cs

@@ -23,6 +23,7 @@ using Venus_RT.Modules;
 using Venus_RT.Backends;
 using Venus_RT.HostWrapper;
 using Venus_RT.Modules.PMs;
+using Venus_RT.FAs;
 using MECF.Framework.Common.DataCenter;
 using Aitex.Core.RT.SCCore;
 using Venus_Core;
@@ -72,6 +73,7 @@ namespace Venus_RT.Instances
             Singleton<DeviceEntity>.Instance.Initialize();
 
             Singleton<FaManager>.Instance.Initialize();
+            Singleton<FaEvent>.Instance.Initialize(PathManager.GetCfgDir() + "EventDefine.xml");
 
             DataCollectionManager.Instance.Initialize(RtInstance.DatabaseName);
 
@@ -119,6 +121,8 @@ namespace Venus_RT.Instances
 
             Singleton<EventManager>.Instance.Terminate();
 
+            Singleton<FaEvent>.Instance.Terminate();
+
             Singleton<LogManager>.Instance.Terminate();
 
             Singleton<DatabaseManager>.Instance.Terminate();

+ 294 - 0
Venus/Venus_RT/Modules/Autotransfer_LP_FA.cs

@@ -0,0 +1,294 @@
+using Aitex.Core.Common;
+using Aitex.Core.RT.Event;
+using Aitex.Core.UI.Control;
+using Aitex.Core.Util;
+using MECF.Framework.Common.Equipment;
+using MECF.Framework.Common.Jobs;
+using MECF.Framework.Common.SubstrateTrackings;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Controls;
+using Venus_RT.FAs;
+using Venus_RT.HostWrapper;
+
+namespace Venus_RT.Modules
+{
+    public interface ISchedulerFACallback
+    {
+        void JobCreated(ControlJobInfo cj, ProcessJobInfo pj);
+        void JobCreateFailed(string module, string lotID, string jobID, string sequenceID);
+        void JobStarted(ControlJobInfo cj, ProcessJobInfo pj);
+        void JobStopped(ControlJobInfo cj, ProcessJobInfo pj);
+        void JobPaused(ControlJobInfo cj, ProcessJobInfo pj);
+        void JobResumed(ControlJobInfo cj, ProcessJobInfo pj);
+        void JobAborted(ControlJobInfo cj, ProcessJobInfo pj);
+
+        void JobFinished(ControlJobInfo cj, ProcessJobInfo pj);
+        void JobFailed(ControlJobInfo cj, ProcessJobInfo pj);
+
+        void JobWaferStart(ControlJobInfo cj, ProcessJobInfo pj, string module, int slotID);
+        void JobWaferEnd(ControlJobInfo cj, ProcessJobInfo pj, string module, int slotID);
+    }
+    public class SchedulerFACallback : ISchedulerFACallback
+    {
+        private const string Port1JobStarted = "Port1JobStarted";
+        private const string Port1JobStopped = "Port1JobStopped";
+        private const string Port1JobPaused = "Port1JobPaused";
+        private const string Port1JobResumed = "Port1JobResumed";
+        private const string Port1JobAborted = "Port1JobAborted";
+        private const string Port1JobFinished = "Port1JobFinished";
+        private const string Port1JobFailed = "Port1JobFailed";
+        private const string Port1SequenceSelected = "Port1SequenceSelected";
+        private const string Port1SequenceSelectFailed = "Port1SequenceSelectFailed";
+        private const string Port1JobWaferStart = "Port1JobWaferStart";
+        private const string Port1JobWaferEnd = "Port1JobWaferEnd";
+
+        private const string Port2JobStarted = "Port2JobStarted";
+        private const string Port2JobStopped = "Port2JobStopped";
+        private const string Port2JobPaused = "Port2JobPaused";
+        private const string Port2JobResumed = "Port2JobResumed";
+        private const string Port2JobAborted = "Port2JobAborted";
+        private const string Port2JobFinished = "Port2JobFinished";
+        private const string Port2JobFailed = "Port2JobFailed";
+        private const string Port2SequenceSelected = "Port2SequenceSelected";
+        private const string Port2SequenceSelectFailed = "Port2SequenceSelectFailed";
+        private const string Port2JobWaferStart = "Port2JobWaferStart";
+        private const string Port2JobWaferEnd = "Port2JobWaferEnd";
+        private Dictionary<ModuleName, string> PortJobWaferStart = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.LP1, Port1JobWaferStart},
+            {ModuleName.LP2, Port2JobWaferStart},
+        };
+
+        private Dictionary<ModuleName, string> PortJobWaferEnd = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.LP1, Port1JobWaferEnd},
+            {ModuleName.LP2, Port2JobWaferEnd},
+        };
+
+        private Dictionary<ModuleName, string> PortJobStarted = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.LP1, Port1JobStarted},
+            {ModuleName.LP2, Port2JobStarted},
+        };
+
+        private Dictionary<ModuleName, string> PortJobStopped = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.LP1, Port1JobStopped},
+            {ModuleName.LP2, Port2JobStopped},
+        };
+        private Dictionary<ModuleName, string> PortJobPaused = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.LP1, Port1JobPaused},
+            {ModuleName.LP2, Port2JobPaused},
+        };
+        private Dictionary<ModuleName, string> PortJobResumed = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.LP1, Port1JobResumed},
+            {ModuleName.LP2, Port2JobResumed},
+        };
+        private Dictionary<ModuleName, string> PortJobAborted = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.LP1, Port1JobAborted},
+            {ModuleName.LP2, Port2JobAborted},
+        };
+        private Dictionary<ModuleName, string> PortJobFinished = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.LP1, Port1JobFinished},
+            {ModuleName.LP2, Port2JobFinished},
+        };
+        private Dictionary<ModuleName, string> PortJobFailed = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.LP1, Port1JobFailed},
+            {ModuleName.LP2, Port2JobFailed},
+        };
+        private Dictionary<ModuleName, string> PortSequenceSelected = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.LP1, Port1SequenceSelected},
+            {ModuleName.LP2, Port2SequenceSelected},
+        };
+        private Dictionary<ModuleName, string> PortSequenceSelectFailed = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.LP1, Port1SequenceSelectFailed},
+            {ModuleName.LP2, Port2SequenceSelectFailed},
+        };
+
+        private Dictionary<ModuleName, string> PortId = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.LP1, "1"},
+            {ModuleName.LP2, "2"},
+        };
+        public SchedulerFACallback()
+        {
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port1JobStarted, Port1JobStarted));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port1JobStopped, Port1JobStopped));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port1JobPaused, Port1JobPaused));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port1JobResumed, Port1JobResumed));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port1JobAborted, Port1JobAborted));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port1JobFinished, Port1JobFinished));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port1JobFailed, Port1JobFailed));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port1SequenceSelected, Port1SequenceSelected));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port1SequenceSelectFailed, Port1SequenceSelectFailed));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port1JobWaferStart, Port1JobWaferStart));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port1JobWaferEnd, Port1JobWaferEnd));
+
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port2JobStarted, Port2JobStarted));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port2JobStopped, Port2JobStopped));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port2JobPaused, Port2JobPaused));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port2JobResumed, Port2JobResumed));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port2JobAborted, Port2JobAborted));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port2JobFinished, Port2JobFinished));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port2JobFailed, Port2JobFailed));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port2SequenceSelected, Port2SequenceSelected));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port2SequenceSelectFailed, Port2SequenceSelectFailed));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port2JobWaferStart, Port2JobWaferStart));
+            FaEvent.AddFaEvent(new PostFAItem("Event", Port2JobWaferEnd, Port2JobWaferEnd));
+        }
+        public void JobCreated(ControlJobInfo cj, ProcessJobInfo pj)
+        {
+            ModuleName module = ModuleHelper.Converter(cj.Module);
+
+            FaEvent.FaNotify(PortSequenceSelected[module], new SerializableDictionary<string, string>()
+            {
+                {DVIDName.LotID,  pj.LotName},
+                {DVIDName.JobID,  pj.ControlJobName},
+                {DVIDName.PortID, PortId[module] },
+                {DVIDName.SequenceID, pj.Sequence.Name }
+            });
+        }
+        public void JobCreateFailed(string module, string lotID, string jobID, string sequenceID)
+        {
+            ModuleName moduleName = ModuleHelper.Converter(module);
+
+            FaEvent.FaNotify(PortSequenceSelectFailed[moduleName], new SerializableDictionary<string, string>()
+            {
+                {DVIDName.LotID,  lotID},
+                {DVIDName.JobID,  jobID},
+                {DVIDName.PortID, PortId[moduleName] },
+                {DVIDName.SequenceID, sequenceID }
+            });
+        }
+        public void JobStarted(ControlJobInfo cj,ProcessJobInfo pj)
+        {
+            ModuleName module= ModuleHelper.Converter(cj.Module);
+            FaEvent.FaNotify(PortJobStarted[module], new SerializableDictionary<string, string>()
+            {
+                {DVIDName.LotID,  pj.LotName},
+                {DVIDName.JobID,  pj.ControlJobName},
+                {DVIDName.PortID, PortId[module] },
+                {DVIDName.SequenceID, pj.Sequence.Name }
+            });
+        }
+
+        public void JobStopped(ControlJobInfo cj, ProcessJobInfo pj)
+        {
+            ModuleName module = ModuleHelper.Converter(cj.Module);
+
+            FaEvent.FaNotify(PortJobStopped[module], new SerializableDictionary<string, string>()
+            {
+                {DVIDName.LotID,  pj.LotName},
+                {DVIDName.JobID,  pj.ControlJobName},
+                {DVIDName.PortID, PortId[module] },
+                {DVIDName.SequenceID, pj.Sequence.Name }
+            });
+        }
+        public void JobPaused(ControlJobInfo cj, ProcessJobInfo pj)
+        {
+            ModuleName module = ModuleHelper.Converter(cj.Module);
+
+            FaEvent.FaNotify(PortJobPaused[module], new SerializableDictionary<string, string>()
+            {
+                {DVIDName.LotID,  pj.LotName},
+                {DVIDName.JobID,  pj.ControlJobName},
+                {DVIDName.PortID, PortId[module] },
+                {DVIDName.SequenceID, pj.Sequence.Name }
+            });
+        }
+        public void JobResumed(ControlJobInfo cj, ProcessJobInfo pj)
+        {
+            ModuleName module = ModuleHelper.Converter(cj.Module);
+
+            FaEvent.FaNotify(PortJobResumed[module], new SerializableDictionary<string, string>()
+            {
+                {DVIDName.LotID,  pj.LotName},
+                {DVIDName.JobID,  pj.ControlJobName},
+                {DVIDName.PortID, PortId[module] },
+                {DVIDName.SequenceID, pj.Sequence.Name }
+            });
+        }
+
+        public void JobAborted(ControlJobInfo cj, ProcessJobInfo pj)
+        {
+            ModuleName module = ModuleHelper.Converter(cj.Module);
+
+            FaEvent.FaNotify(PortJobAborted[module], new SerializableDictionary<string, string>()
+            {
+                {DVIDName.LotID,  cj.LotName},
+                {DVIDName.JobID,  cj.Name},
+                {DVIDName.PortID, PortId[module] },
+                {DVIDName.SequenceID, "" }
+            });
+        }
+        public void JobFinished(ControlJobInfo cj, ProcessJobInfo pj)
+        {
+            ModuleName module = ModuleHelper.Converter(cj.Module);
+
+            int count = pj.SlotWafers.Count;
+            FaEvent.FaNotify(PortJobFinished[module], new SerializableDictionary<string, string>()
+            {
+                {DVIDName.LotID,  pj.LotName},
+                {DVIDName.JobID,  pj.ControlJobName},
+                {DVIDName.PortID, PortId[module] },
+                {DVIDName.SequenceID, pj.Sequence.Name },
+                {DVIDName.ProcessedWaferCount, count.ToString() },
+            });
+        }
+
+        public void JobFailed(ControlJobInfo cj, ProcessJobInfo pj)
+        {
+            ModuleName module = ModuleHelper.Converter(cj.Module);
+
+            FaEvent.FaNotify(PortJobFailed[module], new SerializableDictionary<string, string>()
+            {
+                {DVIDName.LotID,  pj.LotName},
+                {DVIDName.JobID,  pj.ControlJobName},
+                {DVIDName.PortID, PortId[module] },
+                {DVIDName.SequenceID, pj.Sequence.Name }
+            });
+        }
+
+        public void JobWaferStart(ControlJobInfo cj, ProcessJobInfo pj, string module1, int slotID)
+        {
+            ModuleName module = ModuleHelper.Converter(cj.Module);
+
+            FaEvent.FaNotify(PortJobWaferStart[module], new SerializableDictionary<string, string>()
+            {
+                {DVIDName.LotID,  pj.LotName},
+                {DVIDName.JobID,  pj.ControlJobName},
+                {DVIDName.PortID, PortId[module] },
+                {DVIDName.SlotID, (slotID+1).ToString() },
+                {DVIDName.CarrierID, cj.CarrierID.ToString()}
+            });
+        }
+
+        public void JobWaferEnd(ControlJobInfo cj, ProcessJobInfo pj, string module1, int slotID)
+        {
+            ModuleName module = ModuleHelper.Converter(cj.Module);
+
+            WaferInfo wafer = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module1), slotID);
+
+            FaEvent.FaNotify(PortJobWaferEnd[module], new SerializableDictionary<string, string>()
+            {
+                {DVIDName.LotID,  pj.LotName},
+                {DVIDName.JobID,  pj.ControlJobName},
+                {DVIDName.PortID, PortId[module] },
+                {DVIDName.SlotID, (slotID+1).ToString() },
+                {DVIDName.CarrierID, cj.CarrierID.ToString()},
+                {DVIDName.WaferProcessResult, (wafer.ProcessState == EnumWaferProcessStatus.Failed ? 0:1).ToString()}
+            });
+        }
+    }
+}

+ 13 - 3
Venus/Venus_RT/Modules/PMs/PMProcessRoutine.cs

@@ -13,6 +13,7 @@ using Venus_Core;
 using System.ServiceModel.Security.Tokens;
 using System.Diagnostics;
 using MECF.Framework.Common.DBCore;
+using Venus_RT.FAs;
 
 namespace Venus_RT.Modules.PMs
 {
@@ -51,7 +52,8 @@ namespace Venus_RT.Modules.PMs
         private Stopwatch _stepTime = new Stopwatch();
         public RecipeResult currentRecipeResult;
         public bool isMaualEndStep;
-        
+        private RecipeFACallback _faCallback;
+
         private double ChillerTemp
         {
             get
@@ -96,6 +98,7 @@ namespace Venus_RT.Modules.PMs
             Name = "Process";
             _pumpDownRoutine = pdRoutine;
             _processHelper = new ProcessHelper(chamber);
+            _faCallback = new RecipeFACallback();
         }
 
         private bool AssignFuns(Recipe recipe)
@@ -126,12 +129,14 @@ namespace Venus_RT.Modules.PMs
             if (_withWafer && WaferManager.Instance.CheckNoWafer(Module.ToString(), 0))
             {
                 Stop($"can not run process, no wafer at {Module}");
+                FaEvent.FaPostAlarm(Module.ToString(), $"can not run process, no wafer at {Module}");
                 return RState.Failed;
             }
 
             if (!_chamber.IsRFGInterlockOn)
             {
                 Stop("射频电源 Interlock条件不满足");
+                FaEvent.FaPostAlarm(Module.ToString(), "射频电源 Interlock条件不满足");
                 return RState.Failed;
             }
 
@@ -152,6 +157,7 @@ namespace Venus_RT.Modules.PMs
             if (recipe == null)
             {
                 Stop($"Load Recipe:{recipeName} failed");
+                FaEvent.FaPostAlarm(Module.ToString(), $"Load Recipe:{recipeName} failed");
                 return RState.Failed;
             }
 
@@ -204,6 +210,7 @@ namespace Venus_RT.Modules.PMs
                 if (AssignFuns(rcp) == false)
                 {
                     Stop($"Associate process alogrithm with recipe:{rcp.Header.Name} failed");
+                    FaEvent.FaPostAlarm(Module.ToString(), $"Associate process alogrithm with recipe:{rcp.Header.Name} failed");
                     return RState.Failed;
                 }
             }
@@ -214,7 +221,7 @@ namespace Venus_RT.Modules.PMs
 
             _tolerance = SC.GetValue<double>($"System.MaxTemperatureToleranceToTarget");
             _OffsetTemp = SC.GetValue<double>($"{Module}.Chiller.ChillerTemperatureOffset");
-
+            _faCallback.RecipeStart(_chamber.Module.ToString(), recipeName);
             WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.InProcess);
             return Runner.Start(Module, Name);
         }
@@ -254,6 +261,7 @@ namespace Venus_RT.Modules.PMs
             else if (status == RState.Failed || status == RState.Timeout)
             {             
                 Runner.Stop($"Pump down to {BasePressure} failed.");
+                FaEvent.FaPostAlarm(Module.ToString(), $"Pump down to {BasePressure} failed.");
                 return true;
             }
 
@@ -300,6 +308,7 @@ namespace Venus_RT.Modules.PMs
                 CurrentRunningRecipe = _currentRecipe.Header.Name;
 
                 Notify($"Recipe:{CurrentRunningRecipe} start");
+                FaEvent.FaPostInfo(Module.ToString(), $"Recipe:{CurrentRunningRecipe} start");
                 return StartNewStep() == RState.Running;
             }
             
@@ -319,6 +328,7 @@ namespace Venus_RT.Modules.PMs
             {
                 UpdateWaferStatus(false);
                 Runner.Stop($"Recipe:{CurrentRunningRecipe}, Step:{_currentStep + 1} Failed");
+                FaEvent.FaPostAlarm(Module.ToString(), $"Recipe:{CurrentRunningRecipe}, Step:{_currentStep + 1} Failed");
                 return true;
             }
             else if(result == RState.End || isMaualEndStep == true)
@@ -351,7 +361,7 @@ namespace Venus_RT.Modules.PMs
                 else
                 {
                     Notify($"Recipe:{CurrentRunningRecipe} finished");
-
+                    FaEvent.FaPostInfo(Module.ToString(), $"Recipe:{CurrentRunningRecipe} finished");
                     UpdateWaferStatus();
                     return !StartNewRecipe();
                 }

+ 287 - 0
Venus/Venus_RT/Modules/PMs/PMProcess_FA.cs

@@ -0,0 +1,287 @@
+using Aitex.Core.Common;
+using Aitex.Core.RT.Event;
+using Aitex.Core.Util;
+using MECF.Framework.Common.CommonData;
+using MECF.Framework.Common.Equipment;
+using MECF.Framework.Common.SubstrateTrackings;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Venus_RT.HostWrapper;
+using Venus_RT.FAs;
+
+namespace Venus_RT.Modules.PMs
+{
+    public interface IRecipeFACallback
+    {
+        void RecipeStart(string module,string recipeName);
+        void RecipeComplete(string module,string recipeName);
+        void RecipeFailed(string module, string recipeName);
+        void RecipeStepStart(string module, string recipeName, int stepNumber);
+        void RecipeStepEnd(string module, string recipeName, int stepNumber, List<FdcDataItem> fdc);
+    }
+    public class RecipeFACallback : IRecipeFACallback
+    {
+        private const string PMARecipeStart = "PMARecipeStart";
+        private const string PMARecipeComplete = "PMARecipeComplete";
+        private const string PMARecipeStepStart = "PMARecipeStepStart";
+        private const string PMARecipeStepEnd = "PMARecipeStepEnd";
+        private const string PMARecipeFailed = "PMARecipeFailed";
+
+        private const string PMBRecipeStart = "PMBRecipeStart";
+        private const string PMBRecipeComplete = "PMBRecipeComplete";
+        private const string PMBRecipeStepStart = "PMBRecipeStepStart";
+        private const string PMBRecipeStepEnd = "PMBRecipeStepEnd";
+        private const string PMBRecipeFailed = "PMBRecipeFailed";
+
+        private const string PMCRecipeStart = "PMCRecipeStart";
+        private const string PMCRecipeComplete = "PMCRecipeComplete";
+        private const string PMCRecipeStepStart = "PMCRecipeStepStart";
+        private const string PMCRecipeStepEnd = "PMCRecipeStepEnd";
+        private const string PMCRecipeFailed = "PMCRecipeFailed";
+
+        private const string PMDRecipeStart = "PMDRecipeStart";
+        private const string PMDRecipeComplete = "PMDRecipeComplete";
+        private const string PMDRecipeStepStart = "PMDRecipeStepStart";
+        private const string PMDRecipeStepEnd = "PMDRecipeStepEnd";
+        private const string PMDRecipeFailed = "PMDRecipeFailed";
+        private Dictionary<ModuleName, string> PMRecipeStart = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.PMA, PMARecipeStart},
+            {ModuleName.PMB, PMBRecipeStart},
+            {ModuleName.PMC, PMCRecipeStart},
+            {ModuleName.PMD, PMDRecipeStart}
+        };
+
+        private Dictionary<ModuleName, string> PMRecipeComplete = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.PMA, PMARecipeComplete},
+            {ModuleName.PMB, PMBRecipeComplete},
+            {ModuleName.PMC, PMCRecipeComplete},
+            {ModuleName.PMD, PMDRecipeComplete},
+        };
+        private Dictionary<ModuleName, string> PMRecipeStepStart = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.PMA, PMARecipeStepStart},
+            {ModuleName.PMB, PMBRecipeStepStart},
+            {ModuleName.PMC, PMCRecipeStepStart},
+            {ModuleName.PMD, PMDRecipeStepStart},
+        };
+        private Dictionary<ModuleName, string> PMRecipeStepEnd = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.PMA, PMARecipeStepEnd},
+            {ModuleName.PMB, PMBRecipeStepEnd},
+            {ModuleName.PMC, PMCRecipeStepEnd},
+            {ModuleName.PMD, PMDRecipeStepEnd},
+        };
+        private Dictionary<ModuleName, string> PMRecipeFailed = new Dictionary<ModuleName, string>()
+        {
+            {ModuleName.PMA, PMARecipeFailed},
+            {ModuleName.PMB, PMBRecipeFailed},
+            {ModuleName.PMC, PMCRecipeFailed},
+            {ModuleName.PMD, PMDRecipeFailed},
+        };
+        private Dictionary<int, string> PortId = new Dictionary<int, string>()
+        {
+            {(int)ModuleName.LP1, "1"},
+            {(int)ModuleName.LP2, "2"},
+        };
+        public RecipeFACallback()
+        {
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMARecipeStart, PMARecipeStart));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMARecipeComplete, PMARecipeComplete));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMARecipeStepStart, PMARecipeStepStart));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMARecipeStepEnd, PMARecipeStepEnd));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMARecipeFailed, PMARecipeFailed));
+
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMBRecipeStart, PMBRecipeStart));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMBRecipeComplete, PMBRecipeComplete));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMBRecipeStepStart, PMBRecipeStepStart));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMBRecipeStepEnd, PMBRecipeStepEnd));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMBRecipeFailed, PMBRecipeFailed));
+
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMCRecipeStart, PMCRecipeStart));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMCRecipeComplete, PMCRecipeComplete));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMCRecipeStepStart, PMCRecipeStepStart));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMCRecipeStepEnd, PMCRecipeStepEnd));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMCRecipeFailed, PMCRecipeFailed));
+
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMDRecipeStart, PMDRecipeStart));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMDRecipeComplete, PMDRecipeComplete));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMDRecipeStepStart, PMDRecipeStepStart));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMDRecipeStepEnd, PMDRecipeStepEnd));
+            FaEvent.AddFaEvent(new PostFAItem("Event", PMDRecipeFailed, PMDRecipeFailed));
+        }
+        public void RecipeComplete(string module, string recipeName)
+        {
+            WaferInfo wafer = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), 0);
+
+            if (wafer.IsEmpty)
+                return;
+
+            ModuleName moduleName = ModuleHelper.Converter(module);
+
+            if (PortId.ContainsKey(wafer.OriginStation))
+            {
+                FaEvent.FaNotify(PMRecipeComplete[moduleName], new SerializableDictionary<string, string>()
+                {
+                    {DVIDName.RecipeID,  recipeName},
+                    {DVIDName.StationName,  module},
+                    {DVIDName.PortID, PortId[wafer.OriginStation]},
+                    {DVIDName.SlotID, (wafer.OriginSlot+1).ToString()},
+                    {DVIDName.LotID, wafer.LotId},
+                    {DVIDName.CarrierID,wafer.OriginCarrierID.ToString() }
+                });
+            }
+            else
+            {
+                FaEvent.FaNotify(PMRecipeComplete[moduleName], new SerializableDictionary<string, string>()
+                {
+                    {DVIDName.RecipeID,  recipeName},
+                    {DVIDName.StationName,  module},
+                    {DVIDName.SlotID, (wafer.OriginSlot+1).ToString()},
+                    {DVIDName.LotID, wafer.LotId},
+                    {DVIDName.CarrierID,wafer.OriginCarrierID.ToString() }
+                });
+            }
+        }
+        public void RecipeFailed(string module, string recipeName)
+        {
+            WaferInfo wafer = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), 0);
+
+            if (wafer.IsEmpty)
+                return;
+
+            ModuleName moduleName = ModuleHelper.Converter(module);
+
+            if (PortId.ContainsKey(wafer.OriginStation))
+            {
+                FaEvent.FaNotify(PMRecipeFailed[moduleName], new SerializableDictionary<string, string>()
+                {
+                    {DVIDName.RecipeID, recipeName},
+                    {DVIDName.StationName, module},
+                    {DVIDName.PortID, PortId[wafer.OriginStation]},
+                    {DVIDName.SlotID, (wafer.OriginSlot + 1).ToString()},
+                    {DVIDName.LotID, wafer.LotId}
+                });
+            }
+            else
+            {
+                FaEvent.FaNotify(PMRecipeFailed[moduleName], new SerializableDictionary<string, string>()
+                {
+                    {DVIDName.RecipeID, recipeName},
+                    {DVIDName.StationName, module},
+                    {DVIDName.SlotID, (wafer.OriginSlot + 1).ToString()},
+                    {DVIDName.LotID, wafer.LotId}
+                });
+            }
+        }
+        public void RecipeStart(string module, string recipeName)
+        {
+            WaferInfo wafer = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), 0);
+
+            if (wafer.IsEmpty)
+                return;
+
+            ModuleName moduleName = ModuleHelper.Converter(module);
+
+            if (PortId.ContainsKey(wafer.OriginStation))
+            {
+                FaEvent.FaNotify(PMRecipeStart[moduleName], new SerializableDictionary<string, string>()
+                {
+                    {DVIDName.RecipeID, recipeName},
+                    {DVIDName.StationName, module},
+                    {DVIDName.PortID, PortId[wafer.OriginStation]},
+                    {DVIDName.SlotID, (wafer.OriginSlot + 1).ToString()},
+                    {DVIDName.LotID, wafer.LotId},
+                    {DVIDName.CarrierID,wafer.OriginCarrierID.ToString() }
+                });
+            }
+            else
+            {
+                FaEvent.FaNotify(PMRecipeStart[moduleName], new SerializableDictionary<string, string>()
+                {
+                    {DVIDName.RecipeID, recipeName},
+                    {DVIDName.StationName, module},
+                    {DVIDName.SlotID, (wafer.OriginSlot + 1).ToString()},
+                    {DVIDName.LotID, wafer.LotId},
+                    {DVIDName.CarrierID,wafer.OriginCarrierID.ToString() }
+                });
+            }
+        }
+        public void RecipeStepEnd(string module, string recipeName, int stepNumber, List<FdcDataItem> fdc)
+        {
+            WaferInfo wafer = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), 0);
+
+            if (wafer.IsEmpty)
+                return;
+
+            ModuleName moduleName = ModuleHelper.Converter(module);
+
+            if (PortId.ContainsKey(wafer.OriginStation))
+            {
+                FaEvent.FaNotify(PMRecipeStepEnd[moduleName], new SerializableDictionary<string, object>()
+                {
+                    {DVIDName.RecipeID, recipeName},
+                    {DVIDName.StationName, module},
+                    {DVIDName.RecipeStepNumber, (stepNumber + 1).ToString()},
+                    {DVIDName.PortID, PortId[wafer.OriginStation]},
+                    {DVIDName.SlotID, (wafer.OriginSlot + 1).ToString()},
+                    {DVIDName.RecipeStepEndDataSummary, fdc},
+                    {DVIDName.LotID, wafer.LotId},
+                    {DVIDName.CarrierID,wafer.OriginCarrierID.ToString() }
+                });
+            }
+            else
+            {
+                FaEvent.FaNotify(PMRecipeStepEnd[moduleName], new SerializableDictionary<string, object>()
+                {
+                    {DVIDName.RecipeID, recipeName},
+                    {DVIDName.StationName, module},
+                    {DVIDName.RecipeStepNumber, (stepNumber + 1).ToString()},
+                    {DVIDName.SlotID, (wafer.OriginSlot + 1).ToString()},
+                    {DVIDName.RecipeStepEndDataSummary, fdc},
+                    {DVIDName.LotID, wafer.LotId},
+                    {DVIDName.CarrierID,wafer.OriginCarrierID.ToString() }
+
+                });
+            }
+        }
+        public void RecipeStepStart(string module, string recipeName, int stepNumber)
+        {
+            WaferInfo wafer = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), 0);
+
+            if (wafer.IsEmpty)
+                return;
+
+            ModuleName moduleName = ModuleHelper.Converter(module);
+            if (PortId.ContainsKey(wafer.OriginStation))
+            {
+                FaEvent.FaNotify(PMRecipeStepStart[moduleName], new SerializableDictionary<string, string>()
+                {
+                    {DVIDName.RecipeID, recipeName},
+                    {DVIDName.StationName, module},
+                    {DVIDName.RecipeStepNumber, (stepNumber + 1).ToString()},
+                    {DVIDName.PortID, PortId[wafer.OriginStation]},
+                    {DVIDName.SlotID, (wafer.OriginSlot + 1).ToString()},
+                    {DVIDName.LotID, wafer.LotId},
+                    {DVIDName.CarrierID,wafer.OriginCarrierID.ToString() }
+                });
+            }
+            else
+            {
+                FaEvent.FaNotify(PMRecipeStepStart[moduleName], new SerializableDictionary<string, string>()
+                {
+                    {DVIDName.RecipeID, recipeName},
+                    {DVIDName.StationName, module},
+                    {DVIDName.RecipeStepNumber, (stepNumber + 1).ToString()},
+                    {DVIDName.SlotID, (wafer.OriginSlot + 1).ToString()},
+                    {DVIDName.LotID, wafer.LotId},
+                    {DVIDName.CarrierID,wafer.OriginCarrierID.ToString() }
+                });
+            }
+        }
+    }
+}

+ 3 - 0
Venus/Venus_RT/Venus_RT.csproj

@@ -151,6 +151,7 @@
     <Compile Include="Devices\TM\JetTM.cs" />
     <Compile Include="Devices\TM\SIASUNRobot.cs" />
     <Compile Include="Devices\VirgoSignalTower.cs" />
+    <Compile Include="FAs\FaEvent.cs" />
     <Compile Include="FAs\FaEventItem.cs" />
     <Compile Include="FAs\FaHost.cs" />
     <Compile Include="FAs\FALogFileCleaner.cs" />
@@ -167,6 +168,7 @@
     <Compile Include="Instances\RtInstance.cs" />
     <Compile Include="Instances\ToolLoader.cs" />
     <Compile Include="Modules\AutoCycle.cs" />
+    <Compile Include="Modules\Autotransfer_LP_FA.cs" />
     <Compile Include="Modules\EFEM\EfemEntity.cs" />
     <Compile Include="Modules\EFEM\EfemHomeRoutine.cs" />
     <Compile Include="Modules\EFEM\EfemPickRoutine.cs" />
@@ -199,6 +201,7 @@
     <Compile Include="Modules\PMs\PMHomeRoutine.cs" />
     <Compile Include="Modules\PMs\PMLeakCheckRoutine.cs" />
     <Compile Include="Modules\PMs\PMProcessRoutine.cs" />
+    <Compile Include="Modules\PMs\PMProcess_FA.cs" />
     <Compile Include="Modules\PMs\PMPurgeRoutine.cs" />
     <Compile Include="Modules\PMs\PMRoutineBase.cs" />
     <Compile Include="Modules\PMs\PMVATPerformanceRoutine.cs" />