2023-03-03 15:42:13 +08:00
|
|
|
|
using Aitex.Core.RT.Device;
|
|
|
|
|
using Aitex.Core.RT.Device.Devices;
|
|
|
|
|
using Aitex.Core.RT.Device.Unit;
|
|
|
|
|
using Aitex.Core.RT.Event;
|
|
|
|
|
using Aitex.Core.RT.Routine;
|
|
|
|
|
using Aitex.Core.RT.SCCore;
|
|
|
|
|
using Mainframe.Devices;
|
|
|
|
|
using MECF.Framework.Common.Equipment;
|
|
|
|
|
using MECF.Framework.Common.SubstrateTrackings;
|
|
|
|
|
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Aligners.HwAligner;
|
|
|
|
|
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.EFEM;
|
|
|
|
|
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robots;
|
|
|
|
|
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robots.RobotBase;
|
|
|
|
|
using System;
|
|
|
|
|
using static MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robots.RobotBase.RobotBaseDevice;
|
|
|
|
|
|
|
|
|
|
namespace Mainframe.EFEMs
|
|
|
|
|
{
|
|
|
|
|
public class EfemBaseRoutine : ModuleRoutine, IRoutine
|
|
|
|
|
{
|
|
|
|
|
private RobotBaseDevice _waferRobot = null;
|
|
|
|
|
private RobotBaseDevice _trayRobot = null;
|
|
|
|
|
private IEFEM _efemDevice;
|
|
|
|
|
|
|
|
|
|
public IoSensor _loadTrayHomeSensor; //Tray定位
|
|
|
|
|
public IoSensor _loadWaferPlaced; //上下对射,检测Wafer有无
|
|
|
|
|
public IoSensor _loadTrayPresence; //检测托盘有无
|
|
|
|
|
public IoSensor _cassAL6Inch; //6寸检测
|
|
|
|
|
public IoSensor _cassAR6Inch; //6寸检测
|
|
|
|
|
public IoSensor _cassBL6Inch; //6寸检测
|
|
|
|
|
|
|
|
|
|
public IoSensor _cassALWaferConvex; //凸片检测
|
|
|
|
|
public IoSensor _cassARWaferConvex; //凸片检测
|
|
|
|
|
public IoSensor _cassBLWaferConvex; //凸片检测
|
|
|
|
|
private Mainframe.Devices.IoInterLock _tmIoInterLock;
|
|
|
|
|
|
|
|
|
|
public IoLift4 _llLift;
|
|
|
|
|
public IoClaw _loadWaferClaw;
|
|
|
|
|
public IoLift4 _unLoadLift;
|
|
|
|
|
public IoClaw _unLoadWaferClaw;
|
|
|
|
|
|
|
|
|
|
private HwAlignerGuide _alignerDevice = null;
|
|
|
|
|
|
|
|
|
|
protected RobotBaseDevice WaferRobot
|
|
|
|
|
{
|
|
|
|
|
get { return _waferRobot; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected RobotBaseDevice TrayRobot
|
|
|
|
|
{
|
|
|
|
|
get { return _trayRobot; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected IEFEM EfemDevice
|
|
|
|
|
{
|
|
|
|
|
get { return _efemDevice; }
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-13 17:37:55 +08:00
|
|
|
|
public EfemBaseRoutine() : base(ModuleName.EFEM.ToString())
|
2023-03-03 15:42:13 +08:00
|
|
|
|
{
|
|
|
|
|
_waferRobot = DEVICE.GetDevice<SicWaferRobot>($"WaferRobot.WaferRobot");
|
|
|
|
|
_trayRobot = DEVICE.GetDevice<SicTrayRobot>($"TrayRobot.TrayRobot");
|
|
|
|
|
_efemDevice = DEVICE.GetDevice<SicEFEM>($"EFEM.EFEM");
|
|
|
|
|
_loadTrayHomeSensor = DEVICE.GetDevice<IoSensor>($"TM.LoadTrayHomeSensor");
|
|
|
|
|
_alignerDevice = DEVICE.GetDevice<HwAlignerGuide>($"Aligner.HiWinAligner");
|
|
|
|
|
_loadWaferPlaced = DEVICE.GetDevice<IoSensor>($"TM.LLWaferPlaced");
|
|
|
|
|
_loadTrayPresence = DEVICE.GetDevice<IoSensor>($"TM.LLTrayPresence");
|
|
|
|
|
_cassBLWaferConvex = DEVICE.GetDevice<IoSensor>($"TM.CassBLWaferConvexSensor");
|
|
|
|
|
_cassALWaferConvex = DEVICE.GetDevice<IoSensor>($"TM.CassALWaferConvexSensor");
|
|
|
|
|
_cassARWaferConvex = DEVICE.GetDevice<IoSensor>($"TM.CassARWaferConvexSensor");
|
|
|
|
|
_cassAL6Inch = DEVICE.GetDevice<IoSensor>($"TM.CassALInch6Sensor");
|
|
|
|
|
_cassAR6Inch = DEVICE.GetDevice<IoSensor>($"TM.CassARInch6Sensor");
|
|
|
|
|
_cassBL6Inch = DEVICE.GetDevice<IoSensor>($"TM.CassBLInch6Sensor");
|
|
|
|
|
_tmIoInterLock = DEVICE.GetDevice<Mainframe.Devices.IoInterLock>("TM.IoInterLock");
|
|
|
|
|
|
|
|
|
|
_llLift= DEVICE.GetDevice<IoLift4>($"LoadLock.LLLift");
|
|
|
|
|
_unLoadLift= DEVICE.GetDevice<IoLift4>($"UnLoad.UnLoadLift");
|
|
|
|
|
|
|
|
|
|
_loadWaferClaw = DEVICE.GetDevice<IoClaw>($"LoadLock.LLWaferClaw");
|
|
|
|
|
_unLoadWaferClaw = DEVICE.GetDevice<IoClaw>($"UnLoad.UnLoadWaferClaw");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual Result Start(params object[] objs)
|
|
|
|
|
{
|
|
|
|
|
return Result.DONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual Result Monitor()
|
|
|
|
|
{
|
|
|
|
|
return Result.DONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void Abort()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void CheckTraySensor(int id)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = Execute(id, () =>
|
|
|
|
|
{
|
|
|
|
|
if (SC.GetValue<bool>($"System.IsSimulatorMode"))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return _loadTrayPresence.Value;
|
|
|
|
|
});
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
Stop($"Sensor[DI-32] check no tray");
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void ClearRobortExtendToDO(int id)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = Execute(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify("Clear RobortExtendTO DO");
|
|
|
|
|
_tmIoInterLock.DoATMRobotExtendLoaLSideEnable = false;
|
|
|
|
|
_tmIoInterLock.DoATMRobotExtendLoaRSideEnable = false;
|
|
|
|
|
_tmIoInterLock.DoATMRobotExtendUnloadEnable = false;
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void Pick(int id, RobotBaseDevice robot, ModuleName source, int slot, int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify($"Pick from {source} {slot + 1} use Blade1 ");
|
|
|
|
|
if (!robot.Pick(MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robots.RobotArmEnum.Blade1, source.ToString(), slot))
|
|
|
|
|
{
|
|
|
|
|
robot.IsBusy = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}, () =>
|
|
|
|
|
{
|
|
|
|
|
if (robot.IsReady())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
}, timeout * 1000);
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
Stop($"Pick failed, error {robot.ErrorCode}");
|
|
|
|
|
robot.Abort();
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT) //timeout
|
|
|
|
|
{
|
|
|
|
|
robot.Abort();
|
|
|
|
|
Stop(string.Format("pick timeout, can not complete in {0} seconds", timeout));
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void ExtendForPick(int id, RobotBaseDevice robot, ModuleName source, int slot, int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify($"ExtendForPick from {source} {slot + 1} use Blade1 ");
|
|
|
|
|
if (!robot.CheckToPostMessage(RobotMsg.ExtendForPick, RobotArmEnum.Blade1, source.ToString(), slot))
|
|
|
|
|
{
|
|
|
|
|
robot.IsBusy = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}, () =>
|
|
|
|
|
{
|
|
|
|
|
if (robot.IsReady())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
}, timeout * 1000);
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
Stop($"ExtendForPick failed, error {robot.ErrorCode}");
|
|
|
|
|
robot.Abort();
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT) //timeout
|
|
|
|
|
{
|
|
|
|
|
Stop(string.Format("ExtendForPick timeout, can not complete in {0} seconds", timeout));
|
|
|
|
|
robot.Abort();
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void ExtendForPlace(int id, RobotBaseDevice robot, ModuleName source, int slot, int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify($"ExtendForPlace to {source} {slot + 1} use Blade1 ");
|
|
|
|
|
if (!robot.CheckToPostMessage(RobotMsg.ExtendForPlace, MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robots.RobotArmEnum.Blade1, source.ToString(), slot))
|
|
|
|
|
{
|
|
|
|
|
robot.IsBusy = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}, () =>
|
|
|
|
|
{
|
|
|
|
|
if (robot.IsReady())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
}, timeout * 1000);
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
Stop($"ExtendForPlace failed, error {robot.ErrorCode}");
|
|
|
|
|
robot.Abort();
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT) //timeout
|
|
|
|
|
{
|
|
|
|
|
Stop(string.Format("ExtendForPlace timeout, can not complete in {0} seconds", timeout));
|
|
|
|
|
robot.Abort();
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void RobotActionComplete(int id, RobotBaseDevice robot, int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify($"Robot Action Complete ");
|
|
|
|
|
if (!robot.CheckToPostMessage(RobotMsg.ActionDone))
|
|
|
|
|
{
|
|
|
|
|
robot.IsBusy = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}, () =>
|
|
|
|
|
{
|
|
|
|
|
if (robot.IsReady())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
}, timeout * 1000);
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
Stop($"Robot Action failed, error {robot.ErrorCode}");
|
|
|
|
|
robot.Abort();
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT) //timeout
|
|
|
|
|
{
|
|
|
|
|
Stop(string.Format("Robot Action timeout, can not complete in {0} seconds", timeout));
|
|
|
|
|
robot.Abort();
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void Place(int id, RobotBaseDevice robot, ModuleName source, int slot, int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify($"Place wafer to {source} {slot + 1} use Blade1 ");
|
|
|
|
|
if (!robot.Place(MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robots.RobotArmEnum.Blade1, source.ToString(), slot))
|
|
|
|
|
{
|
|
|
|
|
robot.IsBusy = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}, () =>
|
|
|
|
|
{
|
|
|
|
|
if (robot.IsReady())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
}, timeout * 1000);
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
Stop($"Place failed, error {robot.ErrorCode}");
|
|
|
|
|
robot.Abort();
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT) //timeout
|
|
|
|
|
{
|
|
|
|
|
robot.Abort();
|
|
|
|
|
Stop(string.Format("Place timeout, can not complete in {0} seconds", timeout));
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void CheckWaferStatuBeforePick(int id, RobotBaseDevice robot, int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify($"Check Wafer Status Before Pick");
|
|
|
|
|
if (!robot.ExecuteCommand(new object[] { true }))
|
|
|
|
|
{
|
|
|
|
|
robot.IsBusy = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}, () =>
|
|
|
|
|
{
|
|
|
|
|
if (robot.IsReady())
|
|
|
|
|
{
|
|
|
|
|
if (WaferManager.Instance.CheckHasWafer(robot.Name, 0))
|
|
|
|
|
{
|
|
|
|
|
EV.PostWarningLog(ModuleName.EFEM.ToString(), "Robot Check Has Wafer!");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
}, timeout * 1000);
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
Stop($"Place failed, error {robot.ErrorCode}");
|
|
|
|
|
robot.Abort();
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT) //timeout
|
|
|
|
|
{
|
|
|
|
|
robot.Abort();
|
|
|
|
|
Stop(string.Format("Place timeout, can not complete in {0} seconds", timeout));
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void CheckWaferStatuAfterPlace(int id, RobotBaseDevice robot,int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify($"Check Wafer Status After Place");
|
|
|
|
|
if (!robot.ExecuteCommand(new object[] { true}))
|
|
|
|
|
{
|
|
|
|
|
robot.IsBusy = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}, () =>
|
|
|
|
|
{
|
|
|
|
|
if (robot.IsReady())
|
|
|
|
|
{
|
|
|
|
|
if (WaferManager.Instance.CheckHasWafer(robot.Name, 0))
|
|
|
|
|
{
|
|
|
|
|
EV.PostWarningLog(ModuleName.EFEM.ToString(), "Place Finished and Robot Check Has Wafer!");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
}, timeout * 1000);
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
Stop($"Place failed, error {robot.ErrorCode}");
|
|
|
|
|
robot.Abort();
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT) //timeout
|
|
|
|
|
{
|
|
|
|
|
robot.Abort();
|
|
|
|
|
Stop(string.Format("Place timeout, can not complete in {0} seconds", timeout));
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void CheckTrayStatuBeforePick(int id, RobotBaseDevice robot, int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify($"Check Tray Status Before Pick");
|
|
|
|
|
if (!robot.ExecuteCommand(new object[] { true }))
|
|
|
|
|
{
|
|
|
|
|
robot.IsBusy = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}, () =>
|
|
|
|
|
{
|
|
|
|
|
if (robot.IsReady())
|
|
|
|
|
{
|
|
|
|
|
if (WaferManager.Instance.CheckHasTray(ModuleHelper.Converter(robot.Name), 0))
|
|
|
|
|
{
|
|
|
|
|
EV.PostWarningLog(ModuleName.EFEM.ToString(), "Robot Check Has Tray!");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
}, timeout * 1000);
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
Stop($"Place failed, error {robot.ErrorCode}");
|
|
|
|
|
robot.Abort();
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT) //timeout
|
|
|
|
|
{
|
|
|
|
|
robot.Abort();
|
|
|
|
|
Stop(string.Format("Place timeout, can not complete in {0} seconds", timeout));
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void Map(int id, RobotBaseDevice robot, ModuleName source, int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify($"Mapping wafer {source}");
|
|
|
|
|
if (!robot.WaferMapping(source))
|
|
|
|
|
{
|
|
|
|
|
robot.IsBusy = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}, () =>
|
|
|
|
|
{
|
|
|
|
|
if (robot.IsReady())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
}, timeout * 1000);
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
Stop($"Mapping failed, error {robot.ErrorCode}");
|
|
|
|
|
robot.Abort();
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT) //timeout
|
|
|
|
|
{
|
|
|
|
|
robot.Abort();
|
|
|
|
|
Stop(string.Format("Mapping timeout, can not complete in {0} seconds", timeout));
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void CheckRobotReady(int id, RobotBaseDevice robot, int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify($"{robot.Name} Check robot ready");
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}, () =>
|
|
|
|
|
{
|
|
|
|
|
if (robot.IsReady())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}, timeout * 1000);
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT)
|
|
|
|
|
{
|
|
|
|
|
robot.Abort();
|
|
|
|
|
Stop($"{robot.Name} timeout, can not complete in {timeout} seconds");
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void RobotHomeExcute(int id, RobotBaseDevice robot, int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = Execute(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify($"{robot.Name} Execute home");
|
|
|
|
|
if (!robot.Home(null))
|
|
|
|
|
{
|
|
|
|
|
EV.PostAlarmLog(Module, $"{robot.Name} Can not home robot");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT) //timeout
|
|
|
|
|
{
|
|
|
|
|
robot.Abort();
|
|
|
|
|
Stop($"{robot.Name} home timeout over {timeout} seconds");
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//关闭Aligner真空
|
|
|
|
|
protected void CloseVacuum(int id, int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify($"Close Vacuum");
|
|
|
|
|
_alignerDevice.Set("CVF", "CVF");
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}, () =>
|
|
|
|
|
{
|
|
|
|
|
return !_alignerDevice.IsBusy;
|
|
|
|
|
|
|
|
|
|
}, timeout * 1000);
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT) //timeout
|
|
|
|
|
{
|
|
|
|
|
Stop($"Aligner Close Vacuum Timeout, over {timeout} seconds");
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Aligner移动到测量中心
|
|
|
|
|
protected void AlignerMoveToMeasure(int id, int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify($"Move to Measure position");
|
|
|
|
|
_alignerDevice.Set("MTM", "MTM");
|
|
|
|
|
return true;
|
|
|
|
|
}, () =>
|
|
|
|
|
{
|
|
|
|
|
return !_alignerDevice.IsBusy;
|
|
|
|
|
|
|
|
|
|
}, timeout * 1000);
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT)
|
|
|
|
|
{
|
|
|
|
|
Stop($"Aligner Move to Measure position Timeout, over {timeout} seconds");
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//检查是否有Wafer
|
|
|
|
|
protected void CheckHaveWafer(int id, int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify($"check wafer exist or not");
|
|
|
|
|
|
|
|
|
|
_alignerDevice.Set("DOC", "DOC");
|
|
|
|
|
return true;
|
|
|
|
|
}, () =>
|
|
|
|
|
{
|
|
|
|
|
if (!_alignerDevice.IsBusy)
|
|
|
|
|
{
|
|
|
|
|
if (_alignerDevice.HaveWafer)
|
|
|
|
|
{
|
|
|
|
|
Notify($"Check result : aligner have wafer, can not place to aligner");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
}, timeout * 1000);
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT)
|
|
|
|
|
{
|
|
|
|
|
Stop($"Aligner Check Wafer Timeout, over {timeout} seconds");
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void SetWaferRobortExtendToDO(int id, ModuleName target, int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify("Set RobortExtendTO DO");
|
|
|
|
|
|
|
|
|
|
_tmIoInterLock.DoATMRobotExtendLoaLSideEnable = false;
|
|
|
|
|
_tmIoInterLock.DoATMRobotExtendLoaRSideEnable = false;
|
|
|
|
|
_tmIoInterLock.DoATMRobotExtendUnloadEnable = false;
|
|
|
|
|
|
|
|
|
|
if (ModuleHelper.IsLoadLock(target) || target == ModuleName.Load)
|
|
|
|
|
{
|
|
|
|
|
if (!_tmIoInterLock.SetWaferRobotExtendLoadEnable(true, out string reasen))
|
|
|
|
|
{
|
|
|
|
|
Notify(reasen);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (target == ModuleName.UnLoad)
|
|
|
|
|
{
|
|
|
|
|
if (!_tmIoInterLock.SetWaferRobotExtendUnLoadEnable(true, out string reasen))
|
|
|
|
|
{
|
|
|
|
|
Notify(reasen);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}, () =>
|
|
|
|
|
{
|
|
|
|
|
if (ModuleHelper.IsLoadLock(target) || target == ModuleName.Load)
|
|
|
|
|
{
|
|
|
|
|
return _tmIoInterLock.DiATMRobotExtendLoadLSideEnableFB;
|
|
|
|
|
}
|
|
|
|
|
else if (target == ModuleName.UnLoad)
|
|
|
|
|
{
|
|
|
|
|
return _tmIoInterLock.DiATMRobotExtendUnloadEnableFB;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}, timeout * 1000);
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT) //timeout
|
|
|
|
|
{
|
|
|
|
|
Stop($"Set Robot extend to Do timeout over {timeout} seconds");
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void SetTrayRobortExtendToDO(int id, ModuleName target, int timeout)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
|
|
|
|
|
{
|
|
|
|
|
Notify("Set RobortExtendTO DO");
|
|
|
|
|
|
|
|
|
|
_tmIoInterLock.DoATMRobotExtendLoaLSideEnable = false;
|
|
|
|
|
_tmIoInterLock.DoATMRobotExtendLoaRSideEnable = false;
|
|
|
|
|
_tmIoInterLock.DoATMRobotExtendUnloadEnable = false;
|
|
|
|
|
|
|
|
|
|
if (ModuleHelper.IsLoadLock(target) || target == ModuleName.Load)
|
|
|
|
|
{
|
|
|
|
|
if (!_tmIoInterLock.SetTrayRobotExtendLoadEnable(true, out string reasen))
|
|
|
|
|
{
|
|
|
|
|
Notify(reasen);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}, () =>
|
|
|
|
|
{
|
|
|
|
|
if (ModuleHelper.IsLoadLock(target) || target == ModuleName.Load)
|
|
|
|
|
{
|
|
|
|
|
return _tmIoInterLock.DiATMRobotExtendLoadRSideEnableFB;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}, timeout * 1000);
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else if (ret.Item2 == Result.TIMEOUT) //timeout
|
|
|
|
|
{
|
|
|
|
|
Stop($"Set Robot extend to Do timeout over {timeout} seconds");
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void CheckLoadTrayPresence(int id)
|
|
|
|
|
{
|
|
|
|
|
Tuple<bool, Result> ret = Execute(id, () =>
|
|
|
|
|
{
|
|
|
|
|
if (SC.GetValue<bool>("LoadLock.TrayPresenceCheckEnable"))
|
|
|
|
|
{
|
|
|
|
|
if (!_loadTrayPresence.Value)
|
|
|
|
|
{
|
|
|
|
|
EV.PostAlarmLog(Module, $"check load Tray Presence sensor false,no Tray in load");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (ret.Item1)
|
|
|
|
|
{
|
|
|
|
|
if (ret.Item2 == Result.FAIL)
|
|
|
|
|
{
|
|
|
|
|
throw (new RoutineFaildException());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw (new RoutineBreakException());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|