773 lines
26 KiB
C#
773 lines
26 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Aitex.Core.Common;
|
|
using Aitex.Core.RT.DataCenter;
|
|
using Aitex.Core.RT.Device.Devices;
|
|
using Aitex.Core.RT.Device.Unit;
|
|
using Aitex.Core.RT.Event;
|
|
using Aitex.Core.RT.IOCore;
|
|
using Aitex.Core.RT.Log;
|
|
using Aitex.Core.RT.OperationCenter;
|
|
using Aitex.Core.RT.SCCore;
|
|
using Aitex.Core.Util;
|
|
using Aitex.Sorter.Common;
|
|
using MECF.Framework.Common.Communications;
|
|
using MECF.Framework.Common.SubstrateTrackings;
|
|
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts.LoadPortBase;
|
|
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts.TDK;
|
|
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robots.RobotBase;
|
|
|
|
|
|
|
|
namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts.OpenStages
|
|
{
|
|
public class OpenStageHHGyy : LoadPortBaseDevice, IConnection
|
|
{
|
|
public EnumLoadPortType PortType { get; set; }
|
|
public bool Initalized { get; set; }
|
|
public bool Error { get; set; }
|
|
public override string InfoPadCarrierType { get; set; } = "";
|
|
public override FoupDoorState DoorState
|
|
{
|
|
get
|
|
{
|
|
return FoupDoorState.Open;
|
|
}
|
|
}
|
|
private IoSensor[] _diInfoPadA;
|
|
private IoSensor[] _diInfoPadB;
|
|
private IoSensor[] _diInfoPadC;
|
|
private IoSensor _diPresence;
|
|
private IoSensor _diWaferProtrude;
|
|
|
|
private Aitex.Core.RT.Device.Unit.IoTrigger _doIndicatorCstPresent;
|
|
private Aitex.Core.RT.Device.Unit.IoTrigger _doIndicatorCstPlacement;
|
|
private Aitex.Core.RT.Device.Unit.IoTrigger _doIndicatorCstA;
|
|
private Aitex.Core.RT.Device.Unit.IoTrigger _doIndicatorCstB;
|
|
private Aitex.Core.RT.Device.Unit.IoTrigger _doIndicatorCstC;
|
|
private Aitex.Core.RT.Device.Unit.IoTrigger _doIndicatorAlarm;
|
|
|
|
|
|
|
|
|
|
private int m_InfoPadIndex;
|
|
private int m_IndicatorPadIndex;
|
|
private RD_TRIG _trigPresentAbsent = new RD_TRIG();
|
|
private RD_TRIG _trigPresentAbsentDely = new RD_TRIG();
|
|
|
|
private RD_TRIG _trigPlacement = new RD_TRIG();
|
|
|
|
private R_TRIG _trigWaferProtrude = new R_TRIG();
|
|
private R_TRIG _trigCoverClosed = new R_TRIG();
|
|
|
|
private R_TRIG _trigDoorOpen = new R_TRIG();
|
|
private R_TRIG _trigDoorClose = new R_TRIG();
|
|
|
|
DeviceTimer _deviceTimer = new DeviceTimer();
|
|
private int _queryPeriod = 0; //ms
|
|
//private bool _isStillThere = false;
|
|
|
|
private bool _isVirtualMode = false;
|
|
private bool _isLoaded = false;
|
|
private string _carrierInformation = "";
|
|
|
|
public override LoadportCassetteState CassetteState
|
|
{
|
|
get
|
|
{
|
|
if (!_diPresence.Value)
|
|
{
|
|
return LoadportCassetteState.Absent;
|
|
}
|
|
if (_diPresence.Value && (m_IndicatorPadIndex == 60 || m_IndicatorPadIndex == 48 || m_IndicatorPadIndex == 15))
|
|
return LoadportCassetteState.Normal;
|
|
return LoadportCassetteState.Unknown;
|
|
|
|
}
|
|
}
|
|
|
|
public string Address { get => ""; }
|
|
|
|
public bool IsConnected => true;
|
|
|
|
public void SetPrensentAbsentDelay(int ms)
|
|
{
|
|
_queryPeriod = ms;
|
|
}
|
|
|
|
public OpenStageHHGyy(string module, string name, IoSensor[] dis, IoTrigger[] indicators, RobotBaseDevice mapRobot) : base(
|
|
module, name, mapRobot)
|
|
{
|
|
OP.Subscribe($"{Name}.SetAndLoad", (string cmd, object[] param) =>
|
|
{
|
|
if (!SetAndLoad(param,out string reason))
|
|
{
|
|
EV.PostWarningLog(Module, $"{Name} can not load, {reason}");
|
|
return false;
|
|
}
|
|
|
|
EV.PostInfoLog(Module, $"{Name} start load");
|
|
return true;
|
|
});
|
|
OP.Subscribe($"{Name}.SetAndMap", (string cmd, object[] param) =>
|
|
{
|
|
if (!SetAndMap(param,out string reason))
|
|
{
|
|
EV.PostWarningLog(Module, $"{Name} can not load, {reason}");
|
|
return false;
|
|
}
|
|
|
|
EV.PostInfoLog(Module, $"{Name} start load");
|
|
return true;
|
|
});
|
|
|
|
DATA.Subscribe($"{Name}.CarrierInformation", () => _carrierInformation);
|
|
|
|
|
|
if (dis == null)
|
|
throw new ArgumentException("DI cannot be null", "diPresent");
|
|
|
|
if (indicators == null)
|
|
throw new ArgumentException("DO indicators cannot be null", "diNoWaferProtrude");
|
|
|
|
if (string.IsNullOrEmpty(name))
|
|
throw new ArgumentException("name cannot be null or empty", "name");
|
|
|
|
_diInfoPadA = new IoSensor[] { dis[0], dis[1] };
|
|
_diInfoPadB = new IoSensor[] { dis[2], dis[3] };
|
|
_diInfoPadC = new IoSensor[] { dis[4], dis[5] };
|
|
|
|
_diPresence = dis[6];
|
|
_diWaferProtrude = dis[7];
|
|
|
|
|
|
_doIndicatorCstPresent = indicators[0];
|
|
|
|
_doIndicatorCstPlacement = indicators[1];
|
|
_doIndicatorCstA = indicators[2];
|
|
_doIndicatorCstB = indicators[3];
|
|
_doIndicatorCstC = indicators[4];
|
|
_doIndicatorAlarm = indicators[5];
|
|
|
|
|
|
|
|
IsMapWaferByLoadPort = false;
|
|
PortType = EnumLoadPortType.OpenStage;
|
|
LoadPortType = "OpenStage";
|
|
Initalized = true;
|
|
IsBusy = false;
|
|
Error = false;
|
|
|
|
m_InfoPadIndex = ((_diInfoPadA[0].Value && _diInfoPadA[1].Value) ? 1 : 0) +
|
|
((_diInfoPadB[0].Value && _diInfoPadB[1].Value) ? 2 : 0) +
|
|
((_diInfoPadC[0].Value && _diInfoPadC[1].Value) ? 4 : 0);
|
|
|
|
InfoPadCarrierType = SC.ContainsItem($"CarrierInfo.CarrierName{m_InfoPadIndex}") ?
|
|
SC.GetStringValue($"CarrierInfo.CarrierName{m_InfoPadIndex}") : "Unknown";
|
|
DockState = FoupDockState.Docked;
|
|
DoorState = FoupDoorState.Open;
|
|
|
|
InfoPadCarrierIndex = 3;
|
|
|
|
|
|
}
|
|
|
|
private bool SetAndMap(object[] param,out string reason)
|
|
{
|
|
_isLoaded = true;
|
|
//InfoPadCarrierIndex = Convert.ToInt16(param[0]);
|
|
return MapWafer(out reason);
|
|
}
|
|
|
|
private bool SetAndLoad(object[] param,out string reason)
|
|
{
|
|
InfoPadCarrierIndex = Convert.ToInt16(param[0]);
|
|
reason = "";
|
|
return true;
|
|
//return Load(out reason);
|
|
}
|
|
|
|
public override bool IsLoaded => _isLoaded;
|
|
|
|
|
|
|
|
protected override bool fStartExecute(object[] param)
|
|
{
|
|
try
|
|
{
|
|
switch (param[0].ToString())
|
|
{
|
|
case "MapWafer":
|
|
if (!IsMapWaferByLoadPort)
|
|
{
|
|
string reason = "";
|
|
if (!IsEnableMapWafer(out reason))
|
|
{
|
|
EV.PostAlarmLog("LoadPort", $"{LPModuleName} is not ready to map wafer:{reason}");
|
|
return false;
|
|
}
|
|
if (MapRobot != null)
|
|
return MapRobot.WaferMapping(LPModuleName, out _);
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
IsBusy = false;
|
|
return false;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LOG.Write(ex);
|
|
EV.PostAlarmLog(Name, $"Parameter invalid");
|
|
return false;
|
|
|
|
}
|
|
}
|
|
public override void Monitor()
|
|
{
|
|
if (_isVirtualMode) return;
|
|
if(SC.ContainsItem($"CarrierInfo.{LPModuleName}CarrierIndex"))
|
|
{
|
|
if ((SC.GetValue<int>($"CarrierInfo.{LPModuleName}CarrierIndex")) != m_InfoPadIndex)
|
|
SC.SetItemValue($"CarrierInfo.{LPModuleName}CarrierIndex", m_InfoPadIndex);
|
|
}
|
|
|
|
//m_InfoPadIndex = ((_diInfoPadA[0].Value && _diInfoPadA[1].Value) ? 1 : 0) +
|
|
// ((_diInfoPadB[0].Value && _diInfoPadB[1].Value) ? 2 : 0) +
|
|
// ((_diInfoPadC[0].Value && _diInfoPadC[1].Value) ? 4 : 0);
|
|
|
|
m_IndicatorPadIndex = (_diInfoPadA[0].Value ? 32 : 0) + (_diInfoPadA[1].Value ? 16 : 0)
|
|
+ (_diInfoPadB[0].Value ? 8 : 0) + (_diInfoPadB[1].Value ? 4 : 0)
|
|
+ (_diInfoPadC[0].Value ? 2 : 0) + (_diInfoPadC[1].Value ? 1 : 0);
|
|
|
|
switch(m_IndicatorPadIndex)
|
|
{
|
|
case 60:
|
|
m_InfoPadIndex = 6;
|
|
break;
|
|
case 48:
|
|
m_InfoPadIndex = 5;
|
|
break;
|
|
case 15:
|
|
m_InfoPadIndex = 3;
|
|
break;
|
|
default:
|
|
m_InfoPadIndex = 0;
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
InfoPadCarrierType = SC.ContainsItem($"CarrierInfo.CarrierName{m_InfoPadIndex}") ?
|
|
SC.GetStringValue($"CarrierInfo.CarrierName{m_InfoPadIndex}") : "Unknown";
|
|
if (_isPlaced)
|
|
{
|
|
SpecCarrierType = InfoPadCarrierType;
|
|
string carrierinfor = SC.ContainsItem($"CarrierInfo.CarrierInformation{InfoPadCarrierIndex}") ?
|
|
SC.GetStringValue($"CarrierInfo.CarrierInformation{InfoPadCarrierIndex}") : "";
|
|
string stationName = SC.GetStringValue($"CarrierInfo.{Name}Station{InfoPadCarrierIndex}");
|
|
_carrierInformation = $"Thickness:{carrierinfor},Station Name:{stationName}";
|
|
}
|
|
else
|
|
{
|
|
SpecCarrierType = "";
|
|
_carrierInformation = "";
|
|
}
|
|
|
|
_doIndicatorAlarm.SetTrigger(MapError, out _);
|
|
|
|
_doIndicatorCstPresent.SetTrigger(_diPresence.Value, out _);
|
|
|
|
|
|
if (CassetteState == LoadportCassetteState.Absent)
|
|
_trigPresentAbsent.CLK = false;
|
|
if (CassetteState == LoadportCassetteState.Normal)
|
|
{
|
|
if (m_InfoPadIndex == 6)
|
|
{
|
|
_doIndicatorCstA.SetTrigger(true, out _);
|
|
_doIndicatorCstB.SetTrigger(false, out _);
|
|
_doIndicatorCstC.SetTrigger(false, out _);
|
|
|
|
_trigPresentAbsent.CLK = true;
|
|
_doIndicatorCstPlacement.SetTrigger(true, out _);
|
|
}
|
|
else if (m_InfoPadIndex == 5)
|
|
{
|
|
_doIndicatorCstA.SetTrigger(false, out _);
|
|
_doIndicatorCstB.SetTrigger(true, out _);
|
|
_doIndicatorCstC.SetTrigger(false, out _);
|
|
|
|
_trigPresentAbsent.CLK = true;
|
|
_doIndicatorCstPlacement.SetTrigger(true, out _);
|
|
}
|
|
else if (m_InfoPadIndex == 3)
|
|
{
|
|
_doIndicatorCstA.SetTrigger(false, out _);
|
|
_doIndicatorCstB.SetTrigger(false, out _);
|
|
_doIndicatorCstC.SetTrigger(true, out _);
|
|
|
|
_trigPresentAbsent.CLK = true;
|
|
_doIndicatorCstPlacement.SetTrigger(true, out _);
|
|
}
|
|
else
|
|
{
|
|
_doIndicatorCstA.SetTrigger(false, out _);
|
|
_doIndicatorCstB.SetTrigger(false, out _);
|
|
_doIndicatorCstC.SetTrigger(false, out _);
|
|
_doIndicatorCstPlacement.SetTrigger(false, out _);
|
|
}
|
|
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
_isLoaded = false;
|
|
_doIndicatorCstA.SetTrigger(false, out _);
|
|
_doIndicatorCstB.SetTrigger(false, out _);
|
|
_doIndicatorCstC.SetTrigger(false, out _);
|
|
_doIndicatorCstPlacement.SetTrigger(false, out _);
|
|
|
|
}
|
|
|
|
if (_trigPresentAbsent.R)
|
|
{
|
|
SetPresent(true);
|
|
SetPlaced(true);
|
|
|
|
}
|
|
|
|
if (_trigPresentAbsent.T)
|
|
{
|
|
SetPresent(false);
|
|
SetPlaced(false);
|
|
}
|
|
var wafers = WaferManager.Instance.GetWafers(LPModuleName);
|
|
int OcrThreshold = SC.GetValue<int>("Process.OCRScoreThreshold");
|
|
foreach(var wafer in wafers)
|
|
{
|
|
if (wafer.IsEmpty)
|
|
continue;
|
|
if (wafer.SubstE90Status != EnumE90Status.Processed)
|
|
continue;
|
|
if (String.IsNullOrEmpty(wafer.LaserMarkerScore))
|
|
continue;
|
|
float waferscore = Convert.ToSingle(wafer.LaserMarkerScore);
|
|
if(waferscore < (float)OcrThreshold)
|
|
{
|
|
wafer.SubstE90Status = EnumE90Status.Aborted;
|
|
wafer.ProcessState = EnumWaferProcessStatus.Failed;
|
|
}
|
|
}
|
|
|
|
|
|
base.Monitor();
|
|
}
|
|
|
|
public override void OnSlotMapRead(string _slotMap)
|
|
{
|
|
if (!IsMapWaferByLoadPort)
|
|
OnActionDone(new object[] { });
|
|
|
|
if (_slotMap.Length != ValidSlotsNumber)
|
|
{
|
|
EV.PostAlarmLog("LoadPort", "Mapping Data Error.");
|
|
}
|
|
int waferindex = 0;
|
|
|
|
for (int i = 0; i < _slotMap.Length; i++)
|
|
{
|
|
// No wafer: "0", Wafer: "1", Crossed:"2", Undefined: "?", Overlapping wafers: "W"
|
|
WaferInfoRt wafer = null;
|
|
switch (_slotMap[i])
|
|
{
|
|
case '0':
|
|
WaferManager.Instance.DeleteWafer(LPModuleName, i);
|
|
CarrierManager.Instance.UnregisterCarrierWafer(Name, i);
|
|
break;
|
|
case '1':
|
|
Int32 thickness = Math.Abs(Convert.ToInt32(MapRobot.ReadMappingUpData[waferindex]) - Convert.ToInt32(MapRobot.ReadMappingDownData[waferindex]));
|
|
Int32 MinThickness = GetMinThickness(_slotMap);
|
|
if (thickness > (MinThickness * m_doubleWaferFactor))
|
|
{
|
|
wafer = WaferManager.Instance.CreateWafer(LPModuleName, i, WaferStatus.Double);
|
|
WaferManager.Instance.UpdateWaferSize(LPModuleName, i, GetCurrentWaferSize());
|
|
CarrierManager.Instance.RegisterCarrierWafer(Name, i, wafer);
|
|
EV.Notify(AlarmLoadPortMapDoubleWafer);
|
|
waferindex++;
|
|
break;
|
|
}
|
|
|
|
|
|
wafer = WaferManager.Instance.CreateWafer(LPModuleName, i, WaferStatus.Normal);
|
|
WaferManager.Instance.UpdateWaferSize(LPModuleName, i, GetCurrentWaferSize());
|
|
CarrierManager.Instance.RegisterCarrierWafer(Name, i, wafer);
|
|
|
|
waferindex++;
|
|
break;
|
|
case '2':
|
|
wafer = WaferManager.Instance.CreateWafer(LPModuleName, i, WaferStatus.Crossed);
|
|
WaferManager.Instance.UpdateWaferSize(LPModuleName, i, GetCurrentWaferSize());
|
|
CarrierManager.Instance.RegisterCarrierWafer(Name, i, wafer);
|
|
EV.Notify(AlarmLoadPortMapCrossedWafer);
|
|
|
|
waferindex++;
|
|
break;
|
|
case 'W':
|
|
wafer = WaferManager.Instance.CreateWafer(LPModuleName, i, WaferStatus.Double);
|
|
WaferManager.Instance.UpdateWaferSize(LPModuleName, i, GetCurrentWaferSize());
|
|
CarrierManager.Instance.RegisterCarrierWafer(Name, i, wafer);
|
|
EV.Notify(AlarmLoadPortMapDoubleWafer);
|
|
|
|
waferindex++;
|
|
break;
|
|
case '?':
|
|
wafer = WaferManager.Instance.CreateWafer(LPModuleName, i, WaferStatus.Unknown);
|
|
WaferManager.Instance.UpdateWaferSize(LPModuleName, i, GetCurrentWaferSize());
|
|
CarrierManager.Instance.RegisterCarrierWafer(Name, i, wafer);
|
|
//NotifyWaferError(Name, i, WaferStatus.Unknown);
|
|
|
|
waferindex++;
|
|
break;
|
|
}
|
|
}
|
|
SerializableDictionary<string, object> dvid = new SerializableDictionary<string, object>();
|
|
|
|
dvid["SlotMap"] = _slotMap;
|
|
dvid["PortID"] = PortID;
|
|
dvid["PORT_CTGRY"] = SpecPortName;
|
|
dvid["CarrierType"] = SpecCarrierType;
|
|
dvid["CarrierID"] = CarrierId;
|
|
|
|
EV.Notify(EventSlotMapAvailable, dvid);
|
|
if (_slotMap.Contains("2"))
|
|
{
|
|
MapError = true;
|
|
EV.Notify(AlarmLoadPortMappingError, new SerializableDictionary<string, object> {
|
|
{"AlarmText","Mapped Crossed wafer." }
|
|
});
|
|
}
|
|
if (_slotMap.Contains("W"))
|
|
{
|
|
MapError = true;
|
|
EV.Notify(AlarmLoadPortMappingError, new SerializableDictionary<string, object> {
|
|
{"AlarmText","Mapped Double wafer." }
|
|
});
|
|
}
|
|
if (_slotMap.Contains("?"))
|
|
{
|
|
MapError = true;
|
|
EV.Notify(AlarmLoadPortMappingError, new SerializableDictionary<string, object> {
|
|
{"AlarmText","Mapped Unknown wafer." }
|
|
});
|
|
}
|
|
|
|
if (LPCallBack != null)
|
|
LPCallBack.MappingComplete(_carrierId, _slotMap);
|
|
|
|
_isMapped = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
private Int32 GetMinThickness(string slotmap)
|
|
{
|
|
Int32 thickness =-1;
|
|
int waferindex = 0;
|
|
foreach(char slot in slotmap)
|
|
{
|
|
if(slot != '0')
|
|
{
|
|
int currentThickness = Math.Abs(Convert.ToInt32(MapRobot.ReadMappingUpData[waferindex]) - Convert.ToInt32(MapRobot.ReadMappingDownData[waferindex]));
|
|
if (thickness > currentThickness || thickness == -1)
|
|
thickness = currentThickness;
|
|
waferindex++;
|
|
}
|
|
}
|
|
return thickness;
|
|
}
|
|
|
|
private int m_doubleWaferFactor
|
|
{
|
|
get
|
|
{
|
|
if (SC.ContainsItem($"LoadPort.{LPModuleName}.DoubleWaferFactor"))
|
|
return SC.GetValue<int>($"LoadPort.{LPModuleName}.DoubleWaferFactor");
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
|
|
public override void Reset()
|
|
{
|
|
base.Reset();
|
|
|
|
//_trigWaferProtrude.RST = true;
|
|
}
|
|
protected override bool fMonitorReset(object[] param)
|
|
{
|
|
IsBusy = false;
|
|
return true;
|
|
}
|
|
|
|
public override bool IsEnableMapWafer(out string reason)
|
|
{
|
|
if (CurrentState == LoadPortStateEnum.Error)
|
|
{
|
|
reason = "In Error State";
|
|
return false;
|
|
}
|
|
if (CassetteState != LoadportCassetteState.Normal)
|
|
{
|
|
reason = "no FOUP placed";
|
|
return false;
|
|
}
|
|
|
|
if (!_diWaferProtrude.Value && !IsBypassProtrusion && CurrentState != LoadPortStateEnum.TransferBlock)
|
|
{
|
|
|
|
//_trigWaferProtrude.CLK = !_diWaferProtrude.Value;
|
|
|
|
//if (_trigWaferProtrude.Q)
|
|
//{
|
|
// EV.Notify(AlarmLoadPortWaferProtrusion);
|
|
//}
|
|
reason = "Found wafer protrude";
|
|
return false;
|
|
}
|
|
if (!_isLoaded)
|
|
{
|
|
reason = "Cassette is not loaded";
|
|
return false;
|
|
}
|
|
//if (!IsReady())
|
|
//{
|
|
// reason = "Not Ready";
|
|
// return false;
|
|
//}
|
|
reason = "";
|
|
return true;
|
|
}
|
|
public override bool MapWafer(out string reason)
|
|
{
|
|
_isLoaded = true;
|
|
|
|
_trigWaferProtrude.RST = true;
|
|
return base.MapWafer(out reason);
|
|
}
|
|
|
|
public override bool Load(out string reason)
|
|
{
|
|
_isLoaded = true;
|
|
reason = "";
|
|
_trigWaferProtrude.RST = true;
|
|
return true;
|
|
}
|
|
|
|
public override bool IsEnableLoad(out string reason)
|
|
{
|
|
if (CurrentState == LoadPortStateEnum.Error)
|
|
{
|
|
reason = "In Error State";
|
|
return false;
|
|
}
|
|
if (CassetteState != LoadportCassetteState.Normal)
|
|
{
|
|
reason = "no FOUP placed";
|
|
return false;
|
|
}
|
|
|
|
if (!_diWaferProtrude.Value && !IsBypassProtrusion && CurrentState != LoadPortStateEnum.TransferBlock)
|
|
{
|
|
//_trigWaferProtrude.CLK = !_diWaferProtrude.Value;
|
|
|
|
//if (_trigWaferProtrude.Q)
|
|
//{
|
|
// EV.Notify(AlarmLoadPortWaferProtrusion);
|
|
//}
|
|
reason = "Found wafer protrude";
|
|
return false;
|
|
}
|
|
reason = "";
|
|
return true;
|
|
}
|
|
public override bool IsEnableTransferWafer(out string reason)
|
|
{
|
|
if (CurrentState == LoadPortStateEnum.Error)
|
|
{
|
|
reason = "In Error State";
|
|
return false;
|
|
}
|
|
if (CassetteState != LoadportCassetteState.Normal)
|
|
{
|
|
reason = "no FOUP placed";
|
|
return false;
|
|
}
|
|
|
|
if (!_diWaferProtrude.Value&& !IsBypassProtrusion)
|
|
{
|
|
//_trigWaferProtrude.CLK = !_diWaferProtrude.Value;
|
|
|
|
//if (_trigWaferProtrude.Q)
|
|
//{
|
|
// EV.Notify(AlarmLoadPortWaferProtrusion);
|
|
//}
|
|
reason = "Found wafer protrude";
|
|
return false;
|
|
}
|
|
if (!_isLoaded)
|
|
{
|
|
reason = "Cassette is not loaded";
|
|
return false;
|
|
}
|
|
|
|
if (!_isMapped)
|
|
{
|
|
reason = "FOUP not mapped";
|
|
return false;
|
|
}
|
|
|
|
foreach(var wafer in WaferManager.Instance.GetWafers(LPModuleName))
|
|
{
|
|
if (wafer.IsEmpty) continue;
|
|
if(wafer.Status == WaferStatus.Crossed)
|
|
{
|
|
reason = "Crossed wafer";
|
|
return false;
|
|
}
|
|
if (wafer.Status == WaferStatus.Double)
|
|
{
|
|
reason = "Double wafer";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
reason = "";
|
|
return true;
|
|
}
|
|
public bool IsBypassProtrusion
|
|
{
|
|
get
|
|
{
|
|
if (SC.ContainsItem($"CarrierInfo.BypassProtrusionDetectCarrier{m_InfoPadIndex}") &&
|
|
SC.GetValue<bool>($"CarrierInfo.BypassProtrusionDetectCarrier{m_InfoPadIndex}"))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
}
|
|
public override bool IsForbidAccessSlotAboveWafer()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
protected override bool fStartUnload(object[] para)
|
|
{
|
|
if (!_isPlaced) return false;
|
|
|
|
|
|
|
|
//_isMapped = false;
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
protected override bool fMonitorUnload(object[] param)
|
|
{
|
|
IsBusy = false;
|
|
return true;
|
|
}
|
|
|
|
public override bool SetIndicator(Indicator light, IndicatorState state, out string reason)
|
|
{
|
|
reason = "";
|
|
switch (light)
|
|
{
|
|
case Indicator.LOAD:
|
|
|
|
break;
|
|
case Indicator.UNLOAD:
|
|
|
|
break;
|
|
case Indicator.ACCESSAUTO:
|
|
|
|
break;
|
|
case Indicator.ALARM:
|
|
if (state == IndicatorState.ON) _doIndicatorAlarm.SetTrigger(true, out _);
|
|
else _doIndicatorAlarm.SetTrigger(false, out _);
|
|
break;
|
|
default:
|
|
reason = "Not support";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool Disconnect()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
protected override bool fStartWrite(object[] param)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
protected override bool fStartRead(object[] param)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|
|
protected override bool fStartLoad(object[] param)
|
|
{
|
|
string reason;
|
|
//if (!IsEnableLoad(out reason))
|
|
//{
|
|
// EV.PostAlarmLog("System", $"{LPModuleName} load fail:{reason}");
|
|
// IsBusy = false;
|
|
// return false;
|
|
//}
|
|
_isLoaded = true;
|
|
IsBusy = false;
|
|
return true;
|
|
|
|
}
|
|
|
|
protected override bool fMonitorLoad(object[] param)
|
|
{
|
|
IsBusy = false;
|
|
return true;
|
|
}
|
|
|
|
|
|
protected override bool fStartInit(object[] param)
|
|
{
|
|
return true;
|
|
}
|
|
protected override bool fMonitorInit(object[] param)
|
|
{
|
|
IsBusy = false;
|
|
return true;
|
|
}
|
|
protected override bool fStartReset(object[] param)
|
|
{
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
}
|
|
}
|