Browse Source

New Efem design

sangwq 1 year ago
parent
commit
5fc13b3f0c

+ 1 - 1
Venus/Venus_RT/Devices/EFEM/EfemBase.cs

@@ -94,7 +94,7 @@ namespace Venus_RT.Devices.EFEM
         public abstract bool PlaceRetract(ModuleName chamber, int slot, Hand hand);
         public abstract bool Pick(ModuleName station, int slot, Hand hand);
         public abstract bool Place(ModuleName station, int slot, Hand hand);
-        public abstract bool Goto(ModuleName station);
+        public abstract bool Goto(ModuleName station, Hand hand);
         public abstract bool Grip(Hand blade, bool isGrip);
         public abstract bool Map(ModuleName mod);
         public abstract bool SetPinUp(ModuleName mod);

+ 580 - 0
Venus/Venus_RT/Devices/EFEM/JetEfem.cs

@@ -0,0 +1,580 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Collections;
+using Venus_Core;
+using Venus_RT.Modules;
+using MECF.Framework.Common.CommonData;
+using MECF.Framework.Common.Equipment;
+using Aitex.Sorter.Common;
+using Aitex.Core.Common;
+using Aitex.Core.RT.SCCore;
+using Aitex.Core.RT.Log;
+using Aitex.Core.Util;
+using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robot;
+using Venus_RT.Devices.YASKAWA;
+
+namespace Venus_RT.Devices.EFEM
+{
+    class JetEfem :EfemBase
+    {
+        private RState _status;
+        private bool _IsHomed;
+        private RobotMoveInfo _robotMoveInfo = new RobotMoveInfo();
+        private readonly Loadport[] _LPMs = new Loadport[2];
+        private readonly SignalTower _signalT = new SignalTower();
+        private readonly AsyncSocket _socket;
+        private EfemMessage _currentMsg;
+        private EfemMessage _revMsg;
+
+        public override RState Status { get { return _status; } }
+        public override bool IsHomed { get { return _IsHomed; } }
+        public override RobotMoveInfo TMRobotMoveInfo { get { return _robotMoveInfo; } }
+        public override ILoadport this[ModuleName mod]
+        {
+            get
+            {
+                if (!ModuleHelper.IsLoadPort(mod))
+                    throw new ApplicationException($"{mod} is NOT Loadport");
+
+                return _LPMs[mod - ModuleName.LP1];
+            }
+        }
+        public JetEfem()
+        {
+            _socket = new AsyncSocket("");
+            _socket.Connect(SC.GetStringValue($"EFEM.IPAddress"));
+            _socket.OnDataChanged += OnReceiveMessage;
+            _socket.OnErrorHappened += OnErrorHappen;
+
+            _status = RState.Init;
+            _IsHomed = false;
+
+        }
+
+        public override void Monitor()
+        {
+
+        }
+        public override void Terminate()
+        {
+
+        }
+        public override void Reset()
+        {
+
+        }
+        public override void SetOnline(bool online)
+        {
+
+        }
+        public override void SetOnline(ModuleName mod, bool online)
+        {
+
+        }
+
+        public override void SetBusy(ModuleName mod, bool online)
+        {
+
+        }
+
+        public override bool HomeAll()
+        {
+            if (!CheckEfemStatus())
+                return false;
+
+            _currentMsg = new EfemMessage
+            {
+                Operation = EfemOperation.Home,
+                Head = EfemMessage.MsgHead.MOV,
+                Parameters = new List<string> { Constant.ModuleString[ModuleName.EFEM] }
+            };
+
+            _status = RState.Running;
+            return _socket.Write(_currentMsg.ToString());
+        }
+        public override bool Home(ModuleName mod)
+        {
+            if (!CheckEfemStatus())
+                return false;
+
+            _currentMsg = new EfemMessage
+            {
+                Operation = EfemOperation.Home,
+                Head = EfemMessage.MsgHead.MOV,
+                Parameters = new List<string> { Constant.ModuleString[mod] }
+            };
+
+            _status = RState.Running;
+            return _socket.Write(_currentMsg.ToString());
+        }
+        public override bool Halt()
+        {
+            return true;
+        }
+
+        public override bool ClearError()
+        {
+            if (!CheckEfemStatus())
+                return false;
+
+            _currentMsg = new EfemMessage
+            {
+                Operation = EfemOperation.ClearError,
+                Head = EfemMessage.MsgHead.SET,
+                Parameters = new List<string> { "CLEAR" }
+            };
+
+            _status = RState.Running;
+            return _socket.Write(_currentMsg.ToString());
+        }
+        public override bool PickExtend(ModuleName chamber, int slot, Hand hand)
+        {
+            if (!CheckEfemStatus())
+                return false;
+
+            _currentMsg = new EfemMessage
+            {
+                Operation = EfemOperation.Extend,
+                Head = EfemMessage.MsgHead.MOV,
+                Parameters = new List<string>
+                {
+                    chamber.ToHWString(),
+                    ExtendPos.GB.ToString(),
+                    Constant.ArmString[hand],
+                }
+            };
+
+            _status = RState.Running;
+            return _socket.Write(_currentMsg.ToString());
+        }
+        public override bool PickRetract(ModuleName chamber, int slot, Hand hand)
+        {
+            if (!CheckEfemStatus())
+                return false;
+
+            _currentMsg = new EfemMessage
+            {
+                Operation = EfemOperation.Extend,
+                Head = EfemMessage.MsgHead.MOV,
+                Parameters = new List<string>
+                {
+                    chamber.ToHWString(),
+                    ExtendPos.G4.ToString(),
+                    Constant.ArmString[hand],
+                }
+            };
+
+            _status = RState.Running;
+            return _socket.Write(_currentMsg.ToString());
+        }
+        public override bool PlaceExtend(ModuleName chamber, int slot, Hand hand)
+        {
+            if (!CheckEfemStatus())
+                return false;
+
+            _currentMsg = new EfemMessage
+            {
+                Operation = EfemOperation.Extend,
+                Head = EfemMessage.MsgHead.MOV,
+                Parameters = new List<string>
+                {
+                    chamber.ToHWString(),
+                    ExtendPos.PB.ToString(),
+                    Constant.ArmString[hand],
+                }
+            };
+
+            _status = RState.Running;
+            return _socket.Write(_currentMsg.ToString());
+        }
+        public override bool PlaceRetract(ModuleName chamber, int slot, Hand hand)
+        {
+            if (!CheckEfemStatus())
+                return false;
+
+            _currentMsg = new EfemMessage
+            {
+                Operation = EfemOperation.Extend,
+                Head = EfemMessage.MsgHead.MOV,
+                Parameters = new List<string>
+                {
+                    chamber.ToHWString(),
+                    ExtendPos.P4.ToString(),
+                    Constant.ArmString[hand],
+                }
+            };
+
+            _status = RState.Running;
+            return _socket.Write(_currentMsg.ToString());
+        }
+        public override bool Pick(ModuleName station, int slot, Hand hand)
+        {
+            if (!CheckEfemStatus())
+                return false;
+
+
+            Position SrcPos = new Position {  Module= station,Slot= (byte)slot };
+            _currentMsg = new EfemMessage
+            {
+                Operation = EfemOperation.Pick,
+                Head = EfemMessage.MsgHead.MOV,
+                Parameters = new List<string>
+                {
+                    SrcPos.ToHWString(),
+                    Constant.ArmString[hand],
+                    WaferSize.WS12.ToString()
+                }
+            };
+
+            _status = RState.Running;
+            return _socket.Write(_currentMsg.ToString());
+        }
+        public override bool Place(ModuleName station, int slot, Hand hand)
+        {
+            if (!CheckEfemStatus())
+                return false;
+
+
+            Position DestPos = new Position { Module = station, Slot = (byte)slot };
+            _currentMsg = new EfemMessage
+            {
+                Operation = EfemOperation.Place,
+                Head = EfemMessage.MsgHead.MOV,
+                Parameters = new List<string>
+                {
+                    DestPos.ToHWString(),
+                    Constant.ArmString[hand],
+                    WaferSize.WS12.ToString()
+                }
+            };
+
+            _status = RState.Running;
+            return _socket.Write(_currentMsg.ToString());
+        }
+        public override bool Goto(ModuleName station, Hand hand)
+        {
+            if (!CheckEfemStatus())
+                return false;
+
+
+            Position DestPos = new Position { Module = station, Slot = (byte)0 };
+            _currentMsg = new EfemMessage
+            {
+                Operation = EfemOperation.Goto,
+                Head = EfemMessage.MsgHead.MOV,
+                Parameters = new List<string>
+                {
+                    DestPos.ToHWString(),
+                    Constant.ArmString[hand],
+                    WaferSize.WS12.ToString()
+                }
+            };
+
+            _status = RState.Running;
+            return _socket.Write(_currentMsg.ToString());
+        }
+        public override bool Grip(Hand blade, bool isGrip)
+        {
+            return true;
+
+        }
+        public override bool Map(ModuleName mod)
+        {
+            if (!CheckEfemStatus())
+                return false;
+
+            _currentMsg = new EfemMessage
+            {
+                Operation = EfemOperation.Map,
+                Head = EfemMessage.MsgHead.MOV,
+                Parameters = new List<string> { Constant.ModuleString[mod] }
+            };
+
+            _status = RState.Running;
+            return _socket.Write(_currentMsg.ToString());
+        }
+        public override bool SetPinUp(ModuleName mod)
+        {
+            if (!CheckEfemStatus())
+                return false;
+
+            _currentMsg = new EfemMessage
+            {
+                Operation = EfemOperation.Lift,
+                Head = EfemMessage.MsgHead.MOV,
+                Parameters = new List<string> { Constant.ModuleString[mod], "UP" }
+            };
+
+            _status = RState.Running;
+            return _socket.Write(_currentMsg.ToString());
+        }
+        public override bool SetPinDown(ModuleName mod)
+        {
+            if (!CheckEfemStatus())
+                return false;
+
+            _currentMsg = new EfemMessage
+            {
+                Operation = EfemOperation.Lift,
+                Head = EfemMessage.MsgHead.MOV,
+                Parameters = new List<string> { Constant.ModuleString[mod], "DOWN" }
+            };
+
+            _status = RState.Running;
+            return _socket.Write(_currentMsg.ToString());
+        }
+        public override bool Align(ModuleName mod, float delayTime, WaferSize size)
+        {
+            return true;
+        } 
+        public override bool SetLamp(LightType light, LightStatus status)
+        {
+            return true;
+        }
+        public override bool Load(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool Unload(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool ReadCarrierId(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool WriteCarrierId(ModuleName mod, string id)
+        {
+            return true;
+        }
+        public override bool ReadTagData(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool WriteTagData(ModuleName mod, string tagData)
+        {
+            return true;
+        }
+        public override bool Dock(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool Undock(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool Clamp(ModuleName mod, bool isUnloadClamp)
+        {
+            return true;
+        }
+        public override bool Unclamp(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool SetThick(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool SetThin(ModuleName mod)
+        {
+            return true;
+        }
+        public override void SetRobotMovingInfo(RobotAction action, Hand hand, ModuleName target)
+        {
+
+        }
+
+        private void OnReceiveMessage(string RevMsg)
+        {
+            string[] msgs = RevMsg.Split('\r');
+
+            foreach (var msg in msgs)
+            {
+                if (string.IsNullOrWhiteSpace(msg)) continue;
+
+                EfemMessage rec_msg = msg.ToMessage();
+
+                switch (rec_msg.Head)
+                {
+                    case EfemMessage.MsgHead.ACK:
+                        _revMsg = rec_msg;
+                        break;
+
+                    case EfemMessage.MsgHead.INF:
+
+                        // 收到INF之后发送ACK确认
+                        string strACK = rec_msg.RawString.Replace("INF", "ACK");
+
+                        _socket.Write(strACK);
+
+                        EfemMessage ack_msg = strACK.ToMessage();
+                        ack_msg.Direct = MsgDirection.To;
+                        _revMsg = rec_msg;
+
+                        OnCommandUpdated(rec_msg);
+                        break;
+
+                    case EfemMessage.MsgHead.EVT:
+                        OnEventUpdated(new EfemEventArgs
+                        {
+                            EvtStr = rec_msg.ToParamString(),
+                            Module = rec_msg.Port,
+                            CommandType = rec_msg.Operation,
+                            DataList = rec_msg.Data
+                        });
+                        break;
+
+                    case EfemMessage.MsgHead.NAK:
+                    case EfemMessage.MsgHead.CAN:
+                    case EfemMessage.MsgHead.ABS:
+                        OnErrorOccurred(rec_msg);
+                        break;
+                }
+            }
+        }
+
+        private void OnErrorHappen(ErrorEventArgs args)
+        {
+
+        }
+
+        private void OnErrorOccurred(EfemMessage message)
+        {
+            string description = string.Empty;
+            switch(message.Head)
+            {
+                case EfemMessage.MsgHead.NAK:
+                    description = Constant.FactorString[message.Factor];
+                    break;
+                case EfemMessage.MsgHead.CAN:
+                    description = Constant.FactorString.ContainsKey(message.Factor) ? Constant.FactorString[message.Factor] : message.Factor;
+                    break;
+                case EfemMessage.MsgHead.ABS:
+                    description = $"{message.Data[0]}, {message.Data[1]}";
+                    break;
+            }
+
+            LOG.Write(eEvent.ERR_EFEM_COMMON_FAILED, ModuleName.EFEM, $"{description}, [{message.Data[0]}], [{message.Factor}]");
+        }
+
+        private void OnEventUpdated(EfemEventArgs eArg)
+        {
+
+            switch (eArg.CommandType)
+            {
+                case EfemOperation.SigStatus:
+                    // EVT:SIGSTAT/Parameter/DATA1/DATA2;
+                    string sParam = eArg.DataList[0];           // "SYSTEM" or "Pn"
+
+                    // DATA1 & DATA2
+                    int nData1 = Convert.ToInt32(eArg.DataList[1], 16);
+                    int nData2 = Convert.ToInt32(eArg.DataList[2], 16);
+
+                    BitArray baData1 = new BitArray(new int[] { nData1 });
+                    BitArray baData2 = new BitArray(new int[] { nData2 });
+
+                    if (0 == string.Compare(sParam, Constant.SYS, true))
+                    {
+                        // EVT:SIGSTAT/System/00000000/00000004;
+                        // DATA1
+
+                        // Post warning and alarm
+                        if (!baData1[0])   // Bit[0] ON=Normal, OFF=Abnormal
+                        {
+                            //EV.Notify(EFEMVacuumPressureError);
+                            LOG.Write(eEvent.ERR_EFEM_COMMON_FAILED, ModuleName.EFEM, "EFEM System vacuum source pressure low");
+
+                            Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.Error);
+                        }
+                        if (!baData1[1])   // Bit[1] ON=Normal, OFF=Abnormal
+                        {
+                            //EV.Notify(EFEMIonizerAlarm);
+                            LOG.Write(eEvent.ERR_EFEM_COMMON_FAILED, ModuleName.EFEM, "EFEM Ionizer compressed air error");
+                            Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.Error);
+                        }
+                        if (!baData1[2])   // Bit[2] ON=Normal, OFF=Abnormal
+                        {
+                            //EV.Notify(EFEMCDAError);
+                            LOG.Write(eEvent.ERR_EFEM_COMMON_FAILED, ModuleName.EFEM, "EFEM System compressed air pressure low");
+                            Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.Error);
+                        }
+                        if (!baData1[4])   // Bit[4] ON=Normal, OFF=Abnormal
+                        {
+                            //EV.Notify(EFEMFlowGaugeSensorError);
+                            LOG.Write(eEvent.ERR_EFEM_COMMON_FAILED, ModuleName.EFEM, "EFEM Flow gauge sensor error");
+                            Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.Error);
+                        }
+                        if (!baData1[5])   // Bit[5] ON=Normal, OFF=Abnormal
+                        {
+                            //EV.Notify(EFEMLeakageAlarm);
+                            LOG.Write(eEvent.ERR_EFEM_COMMON_FAILED, ModuleName.EFEM, "EFEM Leakage alarm");
+                            Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.Error);
+                        }
+                        if (!baData1[10])   // Bit[10] ON=Normal, OFF=Abnormal
+                        {
+                            //EV.Notify(EFEMIonizerAlarm);
+                            LOG.Write(eEvent.ERR_EFEM_COMMON_FAILED, ModuleName.EFEM, "EFEM Ionizer alarm");
+                            Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.Error);
+                        }
+                        if (!baData1[11])   // Bit[11] ON=Normal, OFF=Abnormal
+                        {
+                            //EV.Notify(EFEMFFUAlarm);
+                            LOG.Write(eEvent.ERR_EFEM_COMMON_FAILED, ModuleName.EFEM, "FFU alarm");
+                            Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.Error);
+                        }
+                        if (!baData1[13])   // Bit[13] ON=RUN, OFF=Maintain
+                        {
+                            //EV.Notify(EFEMOffline);
+                            LOG.Write(eEvent.ERR_EFEM_COMMON_FAILED, ModuleName.EFEM, "EFEM switch to Maintain mode, HomeAll to recover");
+                        }
+                        // DATA2
+                        _signalT.ChangeLightStatus(LightType.RED, baData2[0] ? LightStatus.ON : baData2[5] ? LightStatus.BLINK : LightStatus.OFF);
+                        _signalT.ChangeLightStatus(LightType.GREEN, baData2[1] ? LightStatus.ON : baData2[6] ? LightStatus.BLINK : LightStatus.OFF);
+                        _signalT.ChangeLightStatus(LightType.YELLOW, baData2[2] ? LightStatus.ON : baData2[7] ? LightStatus.BLINK : LightStatus.OFF);
+                        _signalT.ChangeLightStatus(LightType.BLUE, baData2[3] ? LightStatus.ON : baData2[8] ? LightStatus.BLINK : LightStatus.OFF);
+                        _signalT.ChangeLightStatus(LightType.WHITE, baData2[4] ? LightStatus.ON : baData2[9] ? LightStatus.BLINK : LightStatus.OFF);
+                        _signalT.ChangeLightStatus(LightType.BUZZER1, baData2[10] ? LightStatus.ON : LightStatus.OFF);
+
+                        /* EFEM 程序中目前没有实现
+                        _RobotErr.CLK = baData2[27]; // bit 27
+
+                        bool bArmNotExtendLLA            = baData2[30]; // bit 30
+                        bool bArmNotExtendLLB            = baData2[31]; // bit 31
+                        */
+                    } // system event
+                    else
+                    {
+                        _LPMs[eArg.Module - ModuleName.LP1].HandleEvent(eArg);
+                    } // FOUP EVENT
+                    break;
+                case EfemOperation.GetWaferInfo:
+                    _LPMs[eArg.Module - ModuleName.LP1].HandleEvent(eArg);
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        private void OnCommandUpdated(EfemMessage message)
+        {
+            if(_currentMsg.Operation != message.Operation)
+            {
+                return;
+            }
+
+            switch(message.Operation)
+            {
+                case EfemOperation.ClearError:
+                case EfemOperation.Pick:
+                case EfemOperation.Place:
+                case EfemOperation.Extend:
+                case EfemOperation.Goto:
+                    _status = RState.End;
+                    break;
+            }
+        }
+    }
+}

+ 208 - 0
Venus/Venus_RT/Devices/JetEfem.cs

@@ -0,0 +1,208 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Venus_Core;
+using MECF.Framework.Common.CommonData;
+using MECF.Framework.Common.Equipment;
+using Aitex.Sorter.Common;
+using Aitex.Core.Common;
+using Aitex.Core.RT.SCCore;
+using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robot;
+
+namespace Venus_RT.Devices.EFEM
+{
+    class JetEfem :EfemBase
+    {
+        private RState _status;
+        private bool _IsHomed;
+        private RobotMoveInfo _robotMoveInfo = new RobotMoveInfo();
+        private readonly Loadport[] _LPMs = new Loadport[2];
+        private readonly AsyncSocket _socket;
+
+        public override RState Status { get { return _status; } }
+        public override bool IsHomed { get { return _IsHomed; } }
+        public override RobotMoveInfo TMRobotMoveInfo { get { return _robotMoveInfo; } }
+        public override ILoadport this[ModuleName mod]
+        {
+            get
+            {
+                if (!ModuleHelper.IsLoadPort(mod))
+                    throw new ApplicationException($"{mod} is NOT Loadport");
+
+                return _LPMs[mod - ModuleName.LP1];
+            }
+        }
+        public JetEfem()
+        {
+            _socket = new AsyncSocket("");
+            _socket.Connect(SC.GetStringValue($"EFEM.IPAddress"));
+            _socket.OnDataChanged += OnReceiveMessage;
+            _socket.OnErrorHappened += OnErrorHappen;
+
+            _status = RState.Init;
+            _IsHomed = false;
+
+        }
+
+        public override void Monitor()
+        {
+
+        }
+        public override void Terminate()
+        {
+
+        }
+        public override void Reset()
+        {
+
+        }
+        public override void SetOnline(bool online)
+        {
+
+        }
+        public override void SetOnline(ModuleName mod, bool online)
+        {
+
+        }
+
+        public override void SetBusy(ModuleName mod, bool online)
+        {
+
+        }
+
+        public override bool HomeAll()
+        {
+            return true;
+        }
+        public override bool Home(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool Halt()
+        {
+            return true;
+        }
+
+        public override bool ClearError()
+        {
+            return true;
+        }
+        public override bool PickExtend(ModuleName chamber, int slot, Hand hand)
+        {
+            return true;
+        }
+        public override bool PickRetract(ModuleName chamber, int slot, Hand hand)
+        {
+            return true;
+        }
+        public override bool PlaceExtend(ModuleName chamber, int slot, Hand hand)
+        {
+            return true;
+        }
+        public override bool PlaceRetract(ModuleName chamber, int slot, Hand hand)
+        {
+            return true;
+        }
+        public override bool Pick(ModuleName station, int slot, Hand hand)
+        {
+            return true;
+        }
+        public override bool Place(ModuleName station, int slot, Hand hand)
+        {
+            return true;
+        }
+        public override bool Goto(ModuleName station)
+        {
+            return true;
+        }
+        public override bool Grip(Hand blade, bool isGrip)
+        {
+            return true;
+
+        }
+        public override bool Map(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool SetPinUp(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool SetPinDown(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool Align(ModuleName mod, float delayTime, WaferSize size)
+        {
+            return true;
+        } 
+        public override bool SetLamp(LightType light, LightStatus status)
+        {
+            return true;
+        }
+        public override bool Load(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool Unload(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool ReadCarrierId(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool WriteCarrierId(ModuleName mod, string id)
+        {
+            return true;
+        }
+        public override bool ReadTagData(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool WriteTagData(ModuleName mod, string tagData)
+        {
+            return true;
+        }
+        public override bool Dock(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool Undock(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool Clamp(ModuleName mod, bool isUnloadClamp)
+        {
+            return true;
+        }
+        public override bool Unclamp(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool SetThick(ModuleName mod)
+        {
+            return true;
+        }
+        public override bool SetThin(ModuleName mod)
+        {
+            return true;
+        }
+        public override void SetRobotMovingInfo(RobotAction action, Hand hand, ModuleName target)
+        {
+
+        }
+
+        private void OnReceiveMessage(string RevMsg)
+        {
+
+        }
+
+        private void OnErrorHappen(ErrorEventArgs args)
+        {
+
+        }
+    }
+}

+ 1 - 1
Venus/Venus_RT/Modules/EFEM/EfemEntity.cs

@@ -501,7 +501,7 @@ namespace Venus_RT.Modules
             else
                 throw new ArgumentException("Argument error");
 
-            _efem.Goto(unit);
+            _efem.Goto(unit, Hand.Blade1);
             return true;
         }
 

+ 118 - 0
Venus/Venus_RT/Modules/EFEM/EfemHomeRoutine.cs

@@ -0,0 +1,118 @@
+using Aitex.Core.RT.Routine;
+using Aitex.Core.RT.SCCore;
+using Aitex.Sorter.Common;
+using Venus_RT.Devices;
+using MECF.Framework.Common.Routine;
+using MECF.Framework.Common.Equipment;
+using MECF.Framework.Common.SubstrateTrackings;
+using Venus_Core;
+using Aitex.Core.RT.Log;
+using Aitex.Core.Util;
+using MECF.Framework.Common.Schedulers;
+using System.Collections.Generic;
+using Venus_RT.Devices.EFEM;
+
+namespace Venus_RT.Modules.EFEM
+{
+    class EfemHomeRoutine : ModuleRoutineBase, IRoutine
+    {
+        private enum HomeStep
+        {
+            ClearError,
+            InitRobot,
+            HomeAllAxes,
+            CheckWaferPresence,
+            End,
+        }
+
+        private enum HomeModuleStep
+        {
+            Home,
+            End,
+        }
+
+        private int _homeTimeout = 30 * 1000;
+        ModuleName _targetModule;
+        EfemBase _efem;
+
+        public EfemHomeRoutine(EfemBase efem) : base(ModuleName.EfemRobot)
+        {
+            _efem = efem;
+        }
+
+        public RState Start(params object[] objs)
+        {
+
+            _targetModule = (ModuleName)objs[0];
+
+            _homeTimeout = SC.GetValue<int>($"EFEM.HomeTimeout") * 1000;
+            return Runner.Start(Module, $"Home {_targetModule}");
+        }
+
+        public RState Monitor()
+        {
+
+            if(_targetModule == ModuleName.System)
+            {
+                Runner.Run((int)HomeStep.ClearError,            ClearError,             IsStepComplete,     _homeTimeout)
+                    .Run((int)HomeStep.InitRobot,               HomeAll,                IsStepComplete,     _homeTimeout)
+                    .Run((int)HomeStep.HomeAllAxes,             HomeAllAxes,            IsStepComplete,     _homeTimeout)
+                    .Run((int)HomeStep.CheckWaferPresence,      CheckWaferPresence,     IsStepComplete,     _homeTimeout)
+                    .End((int)HomeStep.End,                     NullFun,                _delay_50ms);
+            }
+            else
+            {
+                Runner.Run((int)HomeModuleStep.Home,    HomeModule,     IsStepComplete,     _homeTimeout)
+                    .End((int)HomeModuleStep.End,       NullFun,        _delay_50ms);
+            }
+
+
+            return Runner.Status;
+        }
+
+        public void Abort()
+        {
+        }
+
+        private bool IsStepComplete()
+        {
+            if (_efem.Status == RState.End)
+            {
+                return true;
+            }
+            else if (_efem.Status != RState.Running)
+            {
+                LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Efem home failed: {_efem.Status}");
+                return true;
+            }
+            else
+                return false;
+        }
+
+        private bool ClearError()
+        {
+            return _efem.ClearError();
+        }
+
+        private bool HomeAll()
+        {
+            return _efem.HomeAll();
+        }
+
+        private bool HomeModule()
+        {
+            return _efem.Home(_targetModule);
+        }
+
+        private bool HomeAllAxes()
+        {
+            return true;
+        }
+
+        private bool CheckWaferPresence()
+        {
+            return true;
+        }
+
+    }
+}

+ 172 - 0
Venus/Venus_RT/Modules/EFEM/EfemPickRoutine.cs

@@ -0,0 +1,172 @@
+using Aitex.Core.RT.Routine;
+using Aitex.Core.RT.SCCore;
+using Aitex.Sorter.Common;
+using Venus_RT.Devices;
+using MECF.Framework.Common.Routine;
+using MECF.Framework.Common.Equipment;
+using MECF.Framework.Common.SubstrateTrackings;
+using Venus_Core;
+using Aitex.Core.RT.Log;
+using Aitex.Core.Util;
+using MECF.Framework.Common.Schedulers;
+using System.Collections.Generic;
+using Venus_RT.Devices.EFEM;
+
+namespace Venus_RT.Modules.EFEM
+{
+    class EfemPickRoutine : ModuleRoutineBase, IRoutine
+    {
+        private enum PickStep
+        {
+            WaitModuleReady,
+            Picking1,
+            Picking2,
+            End,
+        }
+
+        private int _moveTimeout = 20 * 1000;
+        private ModuleName _targetModule = ModuleName.System;
+        int _targetSlot;
+        int _targetSlot2;
+        Hand _hand;
+        Hand _hand2;
+        EfemBase _efem;
+        bool _bDoublePick = false;
+
+        public EfemPickRoutine(EfemBase efem) : base(ModuleName.EfemRobot)
+        {
+            _efem = efem;
+        }
+
+        public RState Start(params object[] objs)
+        {
+            if (!_efem.IsHomed)
+            {
+                LOG.Write(eEvent.ERR_EFEM_COMMON_FAILED, Module, $"EFEM is not homed, please home it first");
+                return RState.Failed;
+            }
+
+            _bDoublePick = false;
+            var pickItem = (Queue<MoveItem>)objs[0];
+            _targetModule = pickItem.Peek().SourceModule;
+            _targetSlot = pickItem.Peek().SourceSlot;
+            _hand = pickItem.Peek().RobotHand;
+
+            if(WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, (int)_hand))
+            {
+                LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Efem robot arm{_hand} already has a wafer, cannot do the pick action");
+                return RState.Failed;
+            }
+
+            if(WaferManager.Instance.CheckNoWafer(_targetModule, _targetSlot))
+            {
+                LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"The target slot: {_targetModule}{_targetSlot} has no wafer, cannot do the pick action");
+                return RState.Failed;
+            }
+
+            if(pickItem.Count >= 2)
+            {
+                if(!ModuleHelper.IsLoadPort(_targetModule))
+                {
+                    LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Wrong double pick command, target is not loadport");
+                    return RState.Failed;
+                }
+
+                _hand2 = _hand != Hand.Blade1 ? Hand.Blade1 : Hand.Blade2;
+                if (WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, (int)_hand2))
+                {
+                    LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Efem robot arm{_hand2} already has a wafer, cannot do the double pick action");
+                    return RState.Failed;
+                }
+
+                _targetSlot2 = pickItem.ToArray()[1].DestinationSlot;
+                if (WaferManager.Instance.CheckNoWafer(_targetModule, _targetSlot2))
+                {
+                    LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"The target slot: {_targetModule}{_targetSlot2} has no wafer, cannot do the double pick action");
+                    return RState.Failed;
+                }
+
+                _bDoublePick = true;
+            }
+
+            _moveTimeout = SC.GetValue<int>($"EFEM.MotionTimeout") * 1000;
+            return Runner.Start(Module, $"Pick from {_targetModule}");
+        }
+
+        public RState Monitor()
+        {
+            if(_bDoublePick)
+            {
+                Runner.Wait((int)PickStep.WaitModuleReady,  WaitModuleReady)
+                        .Run((int)PickStep.Picking1,        Pick1,          Pick1Done,      _moveTimeout)
+                        .Run((int)PickStep.Picking2,        Pick2,          Pick2Done,      _moveTimeout)
+                        .End((int)PickStep.End,             ActionDone);
+            }
+            else
+            {
+                Runner.Wait((int)PickStep.WaitModuleReady, WaitModuleReady)
+                        .Run((int)PickStep.Picking1,        Pick1,          Pick1Done,      _moveTimeout)
+                        .End((int)PickStep.End,             ActionDone);
+            }
+
+            return Runner.Status;
+        }
+
+        public void Abort()
+        {
+            _efem.Halt();
+        }
+
+        private bool WaitModuleReady()
+        {
+            return true;
+        }
+
+        private bool Pick1()
+        {
+            return _efem.Pick(_targetModule, _targetSlot, _hand);
+        }
+
+        private bool Pick1Done()
+        {
+            if (_efem.Status == RState.End)
+            {
+                WaferManager.Instance.WaferMoved(_targetModule, _targetSlot, ModuleName.EfemRobot, (int)_hand);
+                return true;
+            }
+            else if (_efem.Status != RState.Running)
+            {
+                LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Efem robot picking failed: {_efem.Status}");
+                return true;
+            }
+
+            return false;
+        }
+
+        private bool Pick2()
+        {
+            return _efem.Pick(_targetModule, _targetSlot2, _hand2);
+        }
+
+        private bool Pick2Done()
+        {
+            if (_efem.Status == RState.End)
+            {
+                WaferManager.Instance.WaferMoved(_targetModule, _targetSlot2, ModuleName.EfemRobot, (int)_hand2);
+                return true;
+            }
+            else if (_efem.Status != RState.Running)
+            {
+                LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Efem robot picking failed: {_efem.Status}");
+                return true;
+            }
+
+            return false;
+        }
+
+        private bool ActionDone()
+        { 
+            return true; 
+        }
+    }
+}

+ 172 - 0
Venus/Venus_RT/Modules/EFEM/EfemPlaceRoutine.cs

@@ -0,0 +1,172 @@
+using Aitex.Core.RT.Routine;
+using Aitex.Core.RT.SCCore;
+using Aitex.Sorter.Common;
+using Venus_RT.Devices;
+using MECF.Framework.Common.Routine;
+using MECF.Framework.Common.Equipment;
+using MECF.Framework.Common.SubstrateTrackings;
+using Venus_Core;
+using Aitex.Core.RT.Log;
+using Aitex.Core.Util;
+using MECF.Framework.Common.Schedulers;
+using System.Collections.Generic;
+using Venus_RT.Devices.EFEM;
+
+namespace Venus_RT.Modules.EFEM
+{
+    class EfemPlaceRoutine : ModuleRoutineBase, IRoutine
+    {
+        private enum PlaceStep
+        {
+            WaitModuleReady,
+            Placing1,
+            Placing2,
+            End,
+        }
+
+        private int _moveTimeout = 20 * 1000;
+        private ModuleName _targetModule = ModuleName.System;
+        int _targetSlot;
+        int _targetSlot2;
+        Hand _hand;
+        Hand _hand2;
+        EfemBase _efem;
+        bool _bDoublePlace = false;
+
+        public EfemPlaceRoutine(EfemBase efem) : base(ModuleName.EfemRobot)
+        {
+            _efem = efem;
+        }
+
+        public RState Start(params object[] objs)
+        {
+            if (!_efem.IsHomed)
+            {
+                LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"EFEM is not homed, please home it first");
+                return RState.Failed;
+            }
+
+            _bDoublePlace = false;
+            var placeItem = (Queue<MoveItem>)objs[0];
+            _targetModule = placeItem.Peek().DestinationModule;
+            _targetSlot = placeItem.Peek().DestinationSlot;
+            _hand = placeItem.Peek().RobotHand;
+
+            if (WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, (int)_hand))
+            {
+                LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Efem robot arm{_hand} already has no wafer, cannot do the place action");
+                return RState.Failed;
+            }
+
+            if (WaferManager.Instance.CheckHasWafer(_targetModule, _targetSlot))
+            {
+                LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"The target: {_targetModule}{_targetSlot} has a wafer, cannot do the place action");
+                return RState.Failed;
+            }
+
+            if (placeItem.Count >= 2)
+            {
+                if (!ModuleHelper.IsLoadPort(_targetModule))
+                {
+                    LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Wrong double place command, target is not loadport");
+                    return RState.Failed;
+                }
+
+                _hand2 = _hand != Hand.Blade1 ? Hand.Blade1 : Hand.Blade2;
+                if (WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, (int)_hand2))
+                {
+                    LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Efem robot arm{_hand2} has no wafer, cannot do the double place action");
+                    return RState.Failed;
+                }
+
+                _targetSlot2 = placeItem.ToArray()[1].DestinationSlot;
+                if (WaferManager.Instance.CheckHasWafer(_targetModule, _targetSlot2))
+                {
+                    LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"The target: {_targetModule}{_targetSlot2} has a wafer, cannot do the double pick action");
+                    return RState.Failed;
+                }
+
+                _bDoublePlace = true;
+            }
+
+            _moveTimeout = SC.GetValue<int>($"EFEM.MotionTimeout") * 1000;
+            return Runner.Start(Module, $"Place to {_targetModule}");
+        }
+
+        public RState Monitor()
+        {
+            if (_bDoublePlace)
+            {
+                Runner.Wait((int)PlaceStep.WaitModuleReady,     WaitModuleReady)
+                        .Run((int)PlaceStep.Placing1,           Place1,         Place1Done,     _moveTimeout)
+                        .Run((int)PlaceStep.Placing2,           Place2,         Place2Done,     _moveTimeout)
+                        .End((int)PlaceStep.End,                ActionDone);
+            }
+            else
+            {
+                Runner.Wait((int)PlaceStep.WaitModuleReady, WaitModuleReady)
+                        .Run((int)PlaceStep.Placing1,           Place1,         Place1Done,     _moveTimeout)
+                        .End((int)PlaceStep.End,                ActionDone);
+            }
+
+            return Runner.Status;
+        }
+
+        public void Abort()
+        {
+            _efem.Halt();
+        }
+
+        private bool WaitModuleReady()
+        {
+            return true;
+        }
+
+        private bool Place1()
+        {
+            return _efem.Place(_targetModule, _targetSlot, _hand);
+        }
+
+        private bool Place1Done()
+        {
+            if (_efem.Status == RState.End)
+            {
+                WaferManager.Instance.WaferMoved(ModuleName.EfemRobot, (int)_hand, _targetModule, _targetSlot);
+                return true;
+            }
+            else if (_efem.Status != RState.Running)
+            {
+                LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Efem robot place failed: {_efem.Status}");
+                return true;
+            }
+
+            return false;
+        }
+
+        private bool Place2()
+        {
+            return _efem.Place(_targetModule, _targetSlot2, _hand2);
+        }
+
+        private bool Place2Done()
+        {
+            if (_efem.Status == RState.End)
+            {
+                WaferManager.Instance.WaferMoved(ModuleName.EfemRobot, (int)_hand2, _targetModule, _targetSlot2);
+                return true;
+            }
+            else if (_efem.Status != RState.Running)
+            {
+                LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Efem robot place failed: {_efem.Status}");
+                return true;
+            }
+
+            return false;
+        }
+
+        private bool ActionDone()
+        {
+            return true;
+        }
+    }
+}

+ 207 - 0
Venus/Venus_RT/Modules/EFEM/EfemSwapRoutine.cs

@@ -0,0 +1,207 @@
+using Aitex.Core.RT.Routine;
+using Aitex.Core.RT.SCCore;
+using Aitex.Sorter.Common;
+using Venus_RT.Devices;
+using MECF.Framework.Common.Routine;
+using MECF.Framework.Common.Equipment;
+using MECF.Framework.Common.SubstrateTrackings;
+using Venus_Core;
+using Aitex.Core.RT.Log;
+using Aitex.Core.Util;
+using MECF.Framework.Common.Schedulers;
+using System.Collections.Generic;
+using Venus_RT.Devices.EFEM;
+
+namespace Venus_RT.Modules.EFEM
+{
+    class EfemSwapRoutine : ModuleRoutineBase, IRoutine
+    {
+        private enum SwapStep
+        {
+            WaitModuleReady,
+            ModulePrepare,
+            OpenSlitDoor,
+            MoveWafer,
+            WaitMaferMoved,
+            CloseSlitDoor,
+            NotifyDone,
+        }
+
+        private readonly EfemBase _efem;
+
+        private int _moveTimeout = 20 * 1000;
+        private ModuleName _targetModule;
+        private LLEntity _llModule;
+        private TMEntity _tmModule;
+
+
+        Queue<MoveItem> _actionList = new Queue<MoveItem>();
+        MoveItem _currentAction;
+
+        public EfemSwapRoutine(EfemBase efem) : base(ModuleName.EfemRobot)
+        {
+            _efem = efem;
+
+            Name = "Swap";
+        }
+        public RState Start(params object[] objs)
+        {
+            if (!_efem.IsHomed)
+            {
+                LOG.Write(eEvent.ERR_EFEM_COMMON_FAILED, Module, $"EFEM is not homed, please home it first");
+                return RState.Failed;
+            }
+
+            _actionList = (Queue<MoveItem>)objs[0];
+            var firtItem = _actionList.Peek();
+            if (ModuleHelper.IsLoadLock(firtItem.SourceModule))
+                _targetModule = firtItem.SourceModule;
+            else if (ModuleHelper.IsLoadLock(firtItem.DestinationModule))
+                _targetModule = firtItem.DestinationModule;
+            else
+            {
+                LOG.Write(eEvent.ERR_TM, Module, $"Invalid move parameter: {firtItem.SourceModule},{firtItem.SourceSlot} => {firtItem.DestinationModule},{firtItem.DestinationSlot} ");
+                return RState.Failed;
+            }
+
+            _llModule = Singleton<RouteManager>.Instance.GetLL(_targetModule);
+            if (_llModule == null)
+            {
+                LOG.Write(eEvent.ERR_TM, Module, $"Invalid Loadlock: {_targetModule}, maybe not installed");
+                return RState.Failed;
+            }
+
+            _tmModule = Singleton<RouteManager>.Instance.GetTM();
+            if(_tmModule == null)
+            {
+                LOG.Write(eEvent.ERR_TM, Module, $"Get TM Entity failed.");
+                return RState.Failed;
+            }
+                
+
+            _moveTimeout = SC.GetValue<int>($"EFEM.MotionTimeout") * 1000;
+
+            return Runner.Start(Module, $"EFEM Swap with {_targetModule}");
+        }
+
+        public RState Monitor()
+        {
+            Runner.Wait((int)SwapStep.WaitModuleReady,  () => _llModule.IsIdle,     _delay_60s)
+                .Run((int)SwapStep.ModulePrepare,       ModulePrepare,              IsModulePrepareReady)
+                .Run((int)SwapStep.OpenSlitDoor,        OpenSlitDoor,               IsSlitDoorOpen)
+                .LoopStart((int)SwapStep.MoveWafer,     loopName(),                 _actionList.Count,      MoveWafer)
+                .LoopEnd((int)SwapStep.WaitMaferMoved,  NullFun,                    WaitWaferMoved,         _moveTimeout)
+                .Run((int)SwapStep.CloseSlitDoor,       CloseSlitDoor,              IsSlitDoorClosed)
+                .End((int)SwapStep.NotifyDone,          NotifyLLDone,               _delay_50ms);
+
+            return Runner.Status;
+        }
+
+        private bool ModulePrepare()
+        {
+            _llModule.PostMsg(LLEntity.MSG.Prepare_EFEM);
+            return true;
+        }
+
+        private string loopName()
+        {
+            return "EFEM Swap";
+        }
+
+        private bool IsModulePrepareReady()
+        {
+            return _llModule.Status == LLEntity.LLStatus.Ready_For_EFEM;
+        }
+
+        private bool OpenSlitDoor()
+        {
+            return _tmModule.TurnEFEMSlitDoor(_targetModule, true, out _);
+        }
+
+        private bool CloseSlitDoor()
+        {
+            return _tmModule.TurnEFEMSlitDoor(_targetModule, false, out _);
+        }
+
+        private bool IsSlitDoorOpen()
+        {
+            return _tmModule.IsLLSlitDoorOpen(_targetModule);
+        }
+
+        private bool IsSlitDoorClosed()
+        {
+            return _tmModule.IsLLSlitDoorClosed(_targetModule);
+        }
+
+        private bool VerifyWaferExistence(MoveItem item)
+        {
+            if (WaferManager.Instance.CheckHasWafer(item.DestinationModule, item.DestinationSlot))
+            {
+                LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Cannot move wafer as desitination {item.DestinationModule},{item.DestinationSlot} already a wafer: ");
+                return false;
+            }
+
+            if (WaferManager.Instance.CheckNoWafer(item.SourceModule, item.SourceSlot))
+            {
+                LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Cannot move wafer as source {item.SourceModule}, {item.SourceSlot} has no wafer");
+                return false;
+            }
+
+            return true;
+        }
+
+        private bool MoveWafer()
+        {
+            _currentAction = _actionList.Dequeue();
+
+            if (!VerifyWaferExistence(_currentAction))
+                return false;
+
+            var wafer = WaferManager.Instance.GetWafer(_currentAction.SourceModule, _currentAction.SourceSlot);
+            LOG.Write(eEvent.EV_EFEM_ROBOT, ModuleName.EfemRobot, $"{wafer.WaferOrigin} will be move from {_currentAction.SourceModule} {_currentAction.SourceSlot + 1}  to {_currentAction.DestinationModule} {_currentAction.DestinationSlot + 1}");
+
+            if (ModuleHelper.IsLoadLock(_currentAction.SourceModule) && ModuleHelper.IsEFEMRobot(_currentAction.DestinationModule))
+            {
+                return _efem.Pick(_currentAction.SourceModule, _currentAction.SourceSlot, (Hand)_currentAction.DestinationSlot);
+            }
+            else if (ModuleHelper.IsEFEMRobot(_currentAction.SourceModule) && ModuleHelper.IsLoadLock(_currentAction.DestinationModule))
+            {
+                return _efem.Place(_currentAction.DestinationModule, _currentAction.DestinationSlot, (Hand)_currentAction.SourceSlot);
+            }
+            else
+            {
+                LOG.Write(eEvent.ERR_EFEM_ROBOT, ModuleName.TM, $"Invalid move parameter, source:{_currentAction.SourceModule},{_currentAction.SourceSlot}, destination: {_currentAction.DestinationModule}, {_currentAction.DestinationSlot}");
+                return false;
+            }
+        }
+
+        private bool WaitWaferMoved()
+        {
+            if (_efem.Status == RState.Running)
+            {
+                return false;
+            }
+            else if (_efem.Status == RState.End)
+            {
+                WaferManager.Instance.WaferMoved(_currentAction.SourceModule, _currentAction.SourceSlot, _currentAction.DestinationModule, _currentAction.DestinationSlot);
+                return true;
+            }
+            else
+            {
+                Runner.Stop($"EFEM Robot moving wafer failed, {_efem.Status}");
+                return true;
+            }
+        }
+
+        private bool NotifyLLDone()
+        {
+            _llModule.PostMsg(LLEntity.MSG.EFEM_Exchange_Ready);
+            return true;
+        }
+
+        public void Abort()
+        {
+            _efem.Halt();
+        }
+    }
+}