using Aitex.Core.Common; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using Aitex.Sorter.Common; using athosRT.tool; using Brooks.WinSECS; using Common.DataCenter; using MECF.Framework.Common.Communications; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.SubstrateTrackings; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts.Fortrend; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts.LoadPortBase; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robots.RobotBase; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Sensors; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Media.Animation; using EV = athosRT.tool.EV; namespace athosRT.Devices.LP { public class FortrendSmifPort : LoadPortBaseDevice, IConnection { public enum LpStepEnum { Step1, Step2, Step3, Step4, Step5, Step6, Step7, Step8, Step9, Step10, Step11, Step12 } private enum STATE { IDLE, WAIT } private bool _isLoaded; private R_TRIG _trigError = new R_TRIG(); private R_TRIG _trigCommunicationError = new R_TRIG(); private R_TRIG _trigRetryConnect = new R_TRIG(); private DeviceTimer _reConnectdTimer = new DeviceTimer(); private PeriodicJob _thread; private object _locker = new object(); private bool _enableLog; private string _errorCode = ""; private DeviceTimer _setStatusTimer = new DeviceTimer(); private int SetStatusTime = 800; private DateTime _dtStartAction; private string _scRoot; private static Dictionary _ErrorDict = new Dictionary { { "1", "PLM Error" }, { "2", "Pod not present" }, { "38", "Latch error" }, { "39", "Pod Remove" }, { "40", "Mask Position Incorrect" }, { "41", "Inhibit Detected while Elevator going Down" }, { "43", "Protrusion Detected" }, { "44", "END EFFECTOR PROTRUSION" }, { "45", "PELLICLE ON TOP" }, { "49", "PLM not Ready" } }; private static Dictionary _RealyMessageDict = new Dictionary { { "OK", "Comment accepted" }, { "BUSY", "Command rejected, LPI is busy" }, { "ALARM", "Command rejected, LPI in alarm state" }, { "NO_POD", "Command rejected, Pod not on LPI" }, { "NOT_READY", "Command rejected, Host interlock not enabled" }, { "INVALID_ARG", "Command rejected, at least one invalid parameter" }, { "CANNOT_PERFORM", "LPI not in the proper state to perform the Host command" }, { "DENIED", "Command rejected for other reason" } }; private static Dictionary _AlarmTimeCodeDict = new Dictionary { { "00", "No alarm" }, { "41", "Alarm occurred during a fetch or open operation" }, { "42", "Alarm occurred during a cassette placement on the process tool" }, { "43", "Alarm occurred during a returning of the minienvironment to Home" }, { "44", "Alarm occurred during a retrieval of the cassette from the Tool" }, { "45", "Alarm occurred during a placement of the cassette on the Pod door" }, { "46", "Non-recoverable fatal error" } }; private static Dictionary _ErrorCodeDict = new Dictionary { { "00", "No error" }, { "01", "Position following error" }, { "02", "LPI not Home" }, { "03", "LPI busy" }, { "04", "Pod removed/missing elevator door" }, { "05", "Aborted by user" }, { "07", "Protrusion sensor failure" }, { "08", "Slot sensor failure" }, { "09", "Wafer presence sensor failure" }, { "10", "Flash sensor failure" }, { "11", "Elevator over-travel limit trip" }, { "13", "Excessive wafer protrusion" }, { "14", "System internal time-out" }, { "15", "Servo command error" }, { "16", "Pod door open time-out" }, { "17", "Pod door close time-out" }, { "18", "Pod hold-down open time-out" }, { "19", "Pod hold-down close time-out" }, { "20", "Wafer seater failed to move toward wafer" }, { "21", "Wafer seater failed to return to Home" }, { "22", "Elevator failed to reach target position" }, { "24", "System error" }, { "27", "Loss of configuration data" }, { "28", "Cassette not present" }, { "29", "Loss of air flow" }, { "31", "Gripper open time out" }, { "32", "Gripper close time out" }, { "33", "Interprocessor communication error" }, { "34", "Gripper overtravel" }, { "35", "Cassette found during unload" } }; protected DeviceTimer counter = new DeviceTimer(); protected DeviceTimer delayTimer = new DeviceTimer(); private int _id; private int _currentTokenId = -1; private Stack _steps = new Stack(); private STATE state; private int loop = 0; private int loopCount = 0; private int loopID = 0; private DeviceTimer timer = new DeviceTimer(); protected RoutineResult RoutineToken = new RoutineResult { Result = RoutineState.Running }; protected Tuple ExecuteResult; public WinSECS wshost { get; set; } public FortrendSMIFHostAgent ha { get; set; } public bool IsQueryComplete { get; set; } public override bool IsLoaded => _isLoaded; public bool IsAutoMode { get; set; } public override bool IsHomed { get; set; } public bool IsPodPresent { get; set; } public bool IsPodLocked { get; set; } public bool IsArmRetract { get; set; } public bool IsAlarm { get; set; } public FunctionEnum FunctionBeingDoneThisTime { get; set; } public CollisionStatusEnum CurrentCollisonStatus { get; set; } public PortReadyStatusEnum CurrentPortReadyStatus { get; set; } public bool IsLiftAtOverTravelLimit { get; set; } public bool IsLiftAtUpLimit { get; set; } public bool IsLiftAtStagePosition { get; set; } public WaferSeaterStateEnum CurrentWaferSeaterStatus { get; set; } public bool IsConnected { get; set; } public string Address { get; private set; } public string AlarmOccurTime { get; private set; } public string AlarmInfo { get; private set; } public int TokenId => _id; public int LoopCounter => loop; public int LoopTotalTime => loopCount; public int Elapsed => (int)(timer.GetElapseTime() / 1000.0); public override WaferSize GetCurrentWaferSize() { return WaferSize.WS8; } public FortrendSmifPort(string module, string name, string scRoot, RobotBaseDevice robot) : base(module, name, robot) { //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Expected O, but got Unknown //IL_025c: Unknown result type (might be due to invalid IL or missing references) base.Module = module; base.Name = name; _scRoot = scRoot; string stringValue = SC.GetStringValue("LoadPort." + base.Name + ".PortName"); if (!Enum.TryParse(name, out var result)) { Enum.TryParse(module, out result); } wshost = new WinSECS(); wshost.PortType = SECS_PORT_TYPE.SECS1_SERIAL; wshost.AutoDevice = true; wshost.DefaultDeviceID = 0; wshost.Secs1.IgnoreSytemBytes = false; wshost.MultipleOpen = true; wshost.MonitorEnabled = true; wshost.Secs1.AcceptDupBlock = false; wshost.Secs1.Interleave = true; wshost.Secs1.RetryCount = 10; wshost.Secs1.SecsHost = true; wshost.Secs1.T1 = 1f; wshost.Secs1.T2 = 10f; wshost.Secs1.T3 = 30u; wshost.Secs1.T4 = 45u; wshost.Secs1.AutoBaud = false; wshost.Secs1.PortName = SC.GetStringValue("LoadPort." + base.Name + ".PortName"); wshost.Secs1.BaudRate = 9600u; ha = new FortrendSMIFHostAgent(wshost, this); wshost.OpenPort((INotifyAgent)(object)ha); if (wshost.PortIsOpen) { IsConnected = true; } Singleton.Instance.Subscribe(base.Name ?? "", this); IsMapWaferByLoadPort = true; } public void OnErrorArrived(string alarmcode, string alarmdecri, string alarmtext) { //EV.PostAlarmLog(base.Name, "AlarmID:(" + alarmdecri + ")" + _ErrorDict[alarmdecri] + ",AlarmText(" + alarmtext + ")"); switch (alarmcode) { case "1": { string text = alarmtext.Replace("Error Code ", "|").Split(new char[1] { '|' })[1]; string text2 = text; string text3 = text2; if (text3 == "52") { IsError = true; EV.PostAlarmLog(base.Name, base.Name + " Has Protrude Error."); base.IsBusy = false; CheckToPostMessage(17, null); } break; } case "2": case "5": case "6": case "43": if (_ErrorDict.ContainsKey(alarmdecri)) { //EV.PostAlarmLog(base.Name, "AlarmID:(" + alarmdecri + ")" + _ErrorDict[alarmdecri] + ",AlarmText(" + alarmtext + ")"); } OnError(); break; case "38": case "39": case "40": case "41": case "44": case "45": case "49": if (_ErrorDict.ContainsKey(alarmdecri)) { //EV.PostWarningLog(base.Name, "AlarmID:(" + alarmdecri + ")" + _ErrorDict[alarmdecri] + ",AlarmText(" + alarmtext + ")"); } break; } } public void OnStausArrived(bool isplace, bool home, bool alarm, bool isbusy) { base.IsBusy = isbusy; IsPodPresent = isplace; IsIdle = home; if (isplace) { OnCarrierPresent(); OnCarrierPlaced(); } } public void OnEventArrived(string eventID) { EV.PostInfoLog(base.Name, "EventId:" + eventID); if (int.TryParse(eventID, out var result)) { switch (result) { case 1: OnCarrierNotPresent(); OnCarrierNotPlaced(); break; case 2: OnCarrierPresent(); OnCarrierPlaced(); break; case 3: IsAutoMode = true; break; case 4: IsAutoMode = false; break; case 11: EV.PostInfoLog("LoadPort", $"{base.LPModuleName} start to load"); break; case 12: _isLoaded = true; DockState = FoupDockState.Docked; break; case 13: OnError("LoadAborted"); break; case 14: EV.PostInfoLog("LoadPort", $"{base.LPModuleName} start to unload"); break; case 15: DockState = FoupDockState.Undocked; _isLoaded = false; IsIdle = true; break; case 16: OnError("UnloadAborted"); break; case 17: //EV.PostInfoLog("Loa dPort", $"{base.LPModuleName} start to home"); break; case 18: DockState = FoupDockState.Undocked; IsHomed = true; IsError = false; EV.PostInfoLog("LoadPort", $"{base.LPModuleName} Home Complete"); break; case 19: OnError("HomeAborted"); break; case 31: IsIdle = true; ClampState = FoupClampState.Close; //LOG.Write($"{base.LPModuleName} Lock Complete", 2, "D:\\sorter\\trunk\\Framework\\RTEquipmentLibrary\\HardwareUnits\\LoadPorts\\Fortrend\\FortrendSmifPort.cs", "OnEventArrived", 241); break; case 32: IsIdle = true; ClampState = FoupClampState.Open; //LOG.Write($"{base.LPModuleName} UnLock Complete", 2, "D:\\sorter\\trunk\\Framework\\RTEquipmentLibrary\\HardwareUnits\\LoadPorts\\Fortrend\\FortrendSmifPort.cs", "OnEventArrived", 246); break; } } } internal void ParseStatus3(byte[] statusValue) { } internal void ParseStatus2(byte[] statusValue) { CurrentPortReadyStatus = (PortReadyStatusEnum)statusValue[0]; } public void ParseStatus1(byte[] statusValue) { IsAutoMode = statusValue[0] == 1; IsPodPresent = statusValue[1] == 1; if (IsPodPresent) { OnCarrierPresent(); OnCarrierPlaced(); } else { OnCarrierNotPresent(); OnCarrierNotPlaced(); } FunctionBeingDoneThisTime = (FunctionEnum)statusValue[3]; CurrentCollisonStatus = (CollisionStatusEnum)statusValue[4]; IsPodLocked = statusValue[5] == 1; } internal void OnAlarmArrived(string alarmData) { EV.PostAlarmLog(base.Name, "alarmdata:" + alarmData); if (alarmData.Length == 4) { string text = alarmData.Substring(0, 2); string text2 = alarmData.Substring(2, 2); AlarmOccurTime = text + "=" + _AlarmTimeCodeDict[text]; AlarmInfo = text2 + "=" + _ErrorCodeDict[text2]; EV.PostAlarmLog(base.Module, base.Module + " " + AlarmOccurTime + ", for " + AlarmInfo); OnError(); IsAlarm = true; } } public override void Reset() { _trigError.RST = true; _trigCommunicationError.RST = true; _trigRetryConnect.RST = true; CheckToPostMessage(5, null); } protected override bool fStartReset(object[] param) { lock (_locker) { SECSTransactionBuilder.BuildS1F5(0).Send(wshost); } return true; } protected override bool fMonitorReset(object[] param) { IsError = false; base.IsBusy = false; return true; } protected override bool fStartInit(object[] param) { //LOG.Write($"{base.LPModuleName} start to home,isHome:{IsHomed}", 2, "D:\\sorter\\trunk\\Framework\\RTEquipmentLibrary\\HardwareUnits\\LoadPorts\\Fortrend\\FortrendSmifPort.cs", "fStartInit", 416); IsHomed = false; lock (_locker) { SECSTransactionBuilder.BuildS1F5(0).Send(wshost); SECSTransactionBuilder.BuildS2F21(11).Send(wshost); } _dtStartAction = DateTime.Now; return true; } protected override bool fMonitorInit(object[] param) { if (DateTime.Now - _dtStartAction > TimeSpan.FromSeconds(TimelimitHome)) { OnError("InitTimeout"); return true; } base.IsBusy = false; return IsHomed; } protected override bool fStartLoad(object[] objs) { ResetRoutine(); return true; } protected override bool fMonitorLoad(object[] param) { base.IsBusy = false; LoadCassette(0, TimelimitAction, OnError); if (ExecuteResult.Item1) { return false; } QueryMap(1, TimelimitAction, OnError); if (ExecuteResult.Item1) { return false; } return true; } protected override bool fStartExecute(object[] param) { try { switch (param[0].ToString()) { case "Unclamp": IsIdle = false; lock (_locker) { SECSTransactionBuilder.BuildS2F21(13).Send(wshost); } break; case "Clamp": IsIdle = false; lock (_locker) { SECSTransactionBuilder.BuildS2F21(12).Send(wshost); } break; case "MapWafer": lock (_locker) { if (!IsMapWaferByLoadPort) { string reason; if (base.MapRobot != null) { return base.MapRobot.WaferMapping(base.LPModuleName, out reason); } return false; } } break; case "QueryState": IsQueryComplete = false; lock (_locker) { SECSTransactionBuilder.BuildS1F5(0).Send(wshost); } break; } _dtStartAction = DateTime.Now; return true; } catch (Exception ex) { //LOG.Write(ex, 2, "D:\\sorter\\trunk\\Framework\\RTEquipmentLibrary\\HardwareUnits\\LoadPorts\\Fortrend\\FortrendSmifPort.cs", "fStartExecute", 521); LogObject.Info(base.Name, "Parameter invalid"); return false; } } protected override bool fMonitorExecuting(object[] param) { base.IsBusy = false; if (DateTime.Now - _dtStartAction > TimeSpan.FromSeconds(TimelimitHome)) { OnError("InitTimeout"); return true; } return IsIdle; } public override bool Stop(out string reason) { lock (_locker) { } return base.Stop(out reason); } public bool QueryMapStatus(out string reason) { reason = string.Empty; lock (_locker) { SECSTransactionBuilder.BuildS1F5(2).Send(wshost); } IsIdle = false; if (!_setStatusTimer.IsIdle()) { _setStatusTimer.Stop(); } _setStatusTimer.Start(0.0); return true; } public bool QueryPortStatus(out string reason) { reason = string.Empty; lock (_locker) { SECSTransactionBuilder.BuildS1F5(0).Send(wshost); } if (!_setStatusTimer.IsIdle()) { _setStatusTimer.Stop(); } _setStatusTimer.Start(0.0); return true; } protected override bool fStartUnload(object[] param) { lock (_locker) { SECSTransactionBuilder.BuildS2F21(10).Send(wshost); } IsIdle = false; _dtStartAction = DateTime.Now; return true; } protected override bool fMonitorUnload(object[] param) { base.IsBusy = false; if (DateTime.Now - _dtStartAction > TimeSpan.FromSeconds(TimelimitAction)) { OnError("UnloadTimeout"); return true; } return IsIdle; } public void OnCarrierNotPlaced() { _isPlaced = false; ConfirmRemoveCarrier(); } public void OnCarrierNotPresent() { _isPresent = false; } public void OnCarrierPlaced() { _isPlaced = true; ConfirmAddCarrier(); } public void OnCarrierPresent() { _isPresent = true; } public override void OnSlotMapRead(string slotMap) { CurrentSlotMapResult = slotMap.Replace("0", "?").Replace("2", "0"); int num = 0; for (int i = 0; i < slotMap.Length; i++) { WaferInfo waferInfo = null; switch (slotMap[i]) { case '2': Singleton.Instance.DeleteWafer(base.LPModuleName, i); Singleton.Instance.UnregisterCarrierWafer(base.Name, i); break; case '1': waferInfo = Singleton.Instance.CreateWafer(base.LPModuleName, i, WaferStatus.Normal, WaferSize.WS8); Singleton.Instance.CheckWaferSize(base.LPModuleName, i, GetCurrentWaferSize()); Singleton.Instance.RegisterCarrierWafer(base.Name, i, waferInfo); break; case '4': waferInfo = Singleton.Instance.CreateWafer(base.LPModuleName, i, WaferStatus.Crossed, WaferSize.WS8); Singleton.Instance.CheckWaferSize(base.LPModuleName, i, GetCurrentWaferSize()); Singleton.Instance.RegisterCarrierWafer(base.Name, i, waferInfo); EV.PostAlarmLog(base.Name, $"{base.Name} Slot:{i + 1} occur crossed. "); num++; break; case 'W': waferInfo = Singleton.Instance.CreateWafer(base.LPModuleName, i, WaferStatus.Double, WaferSize.WS8); Singleton.Instance.CheckWaferSize(base.LPModuleName, i, GetCurrentWaferSize()); Singleton.Instance.RegisterCarrierWafer(base.Name, i, waferInfo); break; case '0': waferInfo = Singleton.Instance.CreateWafer(base.LPModuleName, i, WaferStatus.Unknown, WaferSize.WS8); Singleton.Instance.CheckWaferSize(base.LPModuleName, i, GetCurrentWaferSize()); Singleton.Instance.RegisterCarrierWafer(base.Name, i, waferInfo); break; } } if (num == 0) { base.MapError = false; } else { base.MapError = true; } SerializableDictionary serializableDictionary = new SerializableDictionary(); serializableDictionary["SlotMap"] = CurrentSlotMapResult; serializableDictionary["PortID"] = base.PortID; serializableDictionary["PORT_CTGRY"] = base.SpecPortName; serializableDictionary["CarrierType"] = SpecCarrierType; serializableDictionary["CarrierIndex"] = InfoPadCarrierIndex; serializableDictionary["InfoPadSensorIndex"] = InfoPadSensorIndex; serializableDictionary["CarrierID"] = base.CarrierId; EV.Notify(EventSlotMapAvailable, serializableDictionary); if (CurrentSlotMapResult.Contains("4")) { base.MapError = true; EV.Notify(base.AlarmLoadPortMapCrossedWafer); EV.Notify(base.AlarmLoadPortMappingError); OnError("MappingError"); } if (CurrentSlotMapResult.Contains("3")) { base.MapError = true; EV.Notify(base.AlarmLoadPortMapDoubleWafer); EV.Notify(base.AlarmLoadPortMappingError); OnError("MappingError"); } if (CurrentSlotMapResult.Contains("W")) { base.MapError = true; EV.Notify(base.AlarmLoadPortMapDoubleWafer); EV.Notify(base.AlarmLoadPortMappingError); OnError("MappingError"); } if (CurrentSlotMapResult.Contains("?")) { base.MapError = true; EV.Notify(base.AlarmLoadPortMapUnknownWafer); EV.Notify(base.AlarmLoadPortMappingError); OnError("MappingError"); } if (base.LPCallBack != null) { base.LPCallBack.MappingComplete(_carrierId, CurrentSlotMapResult); } _isMapped = true; } public override void Terminate() { } public override void Monitor() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) if (!IsConnected && ha != null && (_reConnectdTimer.IsIdle() || _reConnectdTimer.GetElapseTime() > 10000.0)) { wshost.ClosePort(); wshost.OpenPort((INotifyAgent)(object)ha); _reConnectdTimer.Start(0.0); } if (IsConnected) { _reConnectdTimer.Stop(); } } public override bool IsEnableTransferWafer(out string reason) { reason = ""; //====为了过检===== //_isLoaded = true; //_isMapped = true; //================= if (_isPresent && _isPlaced && _isLoaded && IsReady() && _isMapped) { return true; } return false; } public override bool Connect() { return true; } public bool Disconnect() { return true; } protected override bool fStartWrite(object[] param) { return true; } protected override bool fStartRead(object[] param) { return true; } public override bool ReadCarrierID(int offset = 0, int length = 16) { return ReadCarrierIDByIndex(); } public override bool ReadCarrierIDByIndex(int offset = 0, int length = 16, int index = 0) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown base.IsBusy = true; SECSTransaction val = new SECSTransaction(100u, 121u); val.Primary.Root.Name = "S100F121"; val.Primary.Root.AddNew("Param1", ""); val.Primary.Root.Item("Param1") .Format = (SECS_FORMAT)44; val.Primary.Root.Item("Param1").Value = ((object)320724); val.ReplyExpected = true; val.Send(wshost); return true; } public override bool WriteCarrierID(string cid, int offset = 0, int length = 16) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown base.IsBusy = true; SECSTransaction val = new SECSTransaction(100u, 119u); val.Primary.Root.Name = "HCS"; val.Primary.Root.AddNew("L4", ""); val.Primary.Root.Item("L4").Format = (SECS_FORMAT)0; val.Primary.Root.Item("L4") .AddNew("NAME", "ECID NAME"); val.Primary.Root.Item("L4") .Item("NAME") .Format = (SECS_FORMAT)44; val.Primary.Root.Item("L4") .Item("NAME") .Value = ((object)50801); val.Primary.Root.Item("L4") .AddNew("VALUE", "ECID VALUE"); val.Primary.Root.Item("L4").Item("VALUE").Format = (SECS_FORMAT)41; val.Primary.Root.Item("L4").Item("VALUE").Value = ((object)1); val.Primary.Root.Item("L4") .AddNew("DateTime", "ECID DateTime"); val.Primary.Root.Item("L4").Item("DateTime").Format = ((SECS_FORMAT)16); val.Primary.Root.Item("L4").Item("DateTime").Value = ((object)"2002031112121200"); val.Primary.Root.Item("L4") .AddNew("DataItem", "ECID DataItem"); val.Primary.Root.Item("L4").Item("DataItem").Format = ((SECS_FORMAT)16); val.Primary.Root.Item("L4").Item("DataItem").Value = ((object)cid); val.ReplyExpected = true; val.Send(wshost); return true; } public override bool WriteCarrierIDByIndex(string cid, int offset = 0, int length = 16, int index = 0) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown base.IsBusy = true; string value = "CST:C080164 TYPE:CST25_AU LOT:" + cid + " QTY:12 FLOW:033000 STATUS:WAITING PRI:3-1 PD:0418A CSRLOT: CLEAN:2021/11/10 19:22:04 EQPGRP:DUMMY STAGE:CP-TEST1 RECIPE:DUMMY EMP:N ;"; SECSTransaction val = new SECSTransaction(100u, 119u); val.Primary.Root.Name = "HCS"; val.Primary.Root.AddNew("L4", ""); val.Primary.Root.Item("L4") .Format = ((SECS_FORMAT)0); val.Primary.Root.Item("L4") .AddNew("NAME", "ECID NAME"); val.Primary.Root.Item("L4") .Item("NAME") .Format = ((SECS_FORMAT)44); val.Primary.Root.Item("L4") .Item("NAME") .Value = ((object)50801); val.Primary.Root.Item("L4") .AddNew("VALUE", "ECID VALUE"); val.Primary.Root.Item("L4").Item("VALUE").Format = ((SECS_FORMAT)41); val.Primary.Root.Item("L4") .Item("VALUE") .Value = ((object)1); val.Primary.Root.Item("L4") .AddNew("DateTime", "ECID DateTime"); val.Primary.Root.Item("L4") .Item("DateTime") .Format = ((SECS_FORMAT)16); val.Primary.Root.Item("L4") .Item("DateTime") .Value = ((object)"2002031112121200"); val.Primary.Root.Item("L4") .AddNew("DataItem", "ECID DataItem"); val.Primary.Root.Item("L4").Item("DataItem").Format = ((SECS_FORMAT)16); val.Primary.Root.Item("L4") .Item("DataItem") .Value = (object)value; val.ReplyExpected = true; val.Send(wshost); return true; } public void LoadCassette(int id, int time, Action error) { Tuple tuple = ExecuteAndWait(id, delegate { EV.PostInfoLog($"{base.LPModuleName}", $"start loading"); string empty = string.Empty; _isLoaded = false; lock (_locker) { SECSTransactionBuilder.BuildS2F21(9).Send(wshost); } return true; }, () => _isLoaded ? new Result?(Result.DONE) : new Result?(Result.RUN), time * 1000); if (tuple.Item1) { if (tuple.Item2 == Result.FAIL) { error("load failed"); } if (tuple.Item2 == Result.TIMEOUT) { error("load timeout"); } } } protected void QueryMap(int id, int time, Action error) { Tuple tuple = ExecuteAndWait(id, delegate { EV.PostInfoLog("System", $"{base.LPModuleName} start to query map"); string empty = string.Empty; _isMapped = false; lock (_locker) { SECSTransactionBuilder.BuildS1F3(new int[2] { 1, 2 }).Send(wshost); } return true; }, () => _isMapped ? new Result?(Result.DONE) : new Result?(Result.RUN), time * 1000); if (tuple.Item1) { if (tuple.Item2 == Result.FAIL) { error("map failed"); } if (tuple.Item2 == Result.TIMEOUT) { error("map timeout"); } } } public void ResetRoutine() { _id = 0; _steps.Clear(); loop = 0; loopCount = 0; state = STATE.IDLE; counter.Start(360000.0); RoutineToken.Result = RoutineState.Running; _currentTokenId = -1; ExecuteResult = Tuple.Create(item1: false, Result.DONE); } protected void PerformRoutineStep(int id, Func execution, RoutineResult result) { if (Acitve(id)) { result.Result = execution(); } } public void StopLoop() { loop = loopCount; } public Tuple Loop(T id, Func func, int count) { int id2 = Convert.ToInt32(id); bool flag = Acitve(id2); if (flag) { if (!func()) { return Tuple.Create(flag, Result.FAIL); } loopID = id2; loopCount = count; next(); return Tuple.Create(item1: true, Result.RUN); } return Tuple.Create(item1: false, Result.RUN); } public Tuple EndLoop(T id, Func func) { int id2 = Convert.ToInt32(id); bool flag = Acitve(id2); if (flag) { if (++loop >= loopCount) { if (!func()) { return Tuple.Create(flag, Result.FAIL); } loop = 0; loopCount = 0; next(); return Tuple.Create(item1: true, Result.RUN); } next(loopID); return Tuple.Create(item1: true, Result.RUN); } return Tuple.Create(item1: false, Result.RUN); } public Tuple ExecuteAndWait(T id, IRoutine routine) { int id2 = Convert.ToInt32(id); if (Acitve(id2)) { if (state == STATE.IDLE) { switch (routine.Start()) { case Result.FAIL: return Tuple.Create(item1: true, Result.FAIL); case Result.DONE: next(); return Tuple.Create(item1: true, Result.DONE); } state = STATE.WAIT; } Result result = routine.Monitor(); int num; switch (result) { case Result.DONE: next(); return Tuple.Create(item1: true, Result.DONE); default: num = ((result == Result.TIMEOUT) ? 1 : 0); break; case Result.FAIL: num = 1; break; } if (num != 0) { return Tuple.Create(item1: true, Result.FAIL); } return Tuple.Create(item1: true, Result.RUN); } return Tuple.Create(item1: false, Result.RUN); } public Tuple ExecuteAndWait(T id, List routines) { int id2 = Convert.ToInt32(id); if (Acitve(id2)) { if (state == STATE.IDLE) { foreach (IRoutine routine in routines) { if (routine.Start() == Result.FAIL) { return Tuple.Create(item1: true, Result.FAIL); } } state = STATE.WAIT; } bool flag = false; bool flag2 = true; foreach (IRoutine routine2 in routines) { Result result = routine2.Monitor(); flag2 = flag2 && (result == Result.FAIL || result == Result.DONE); flag = flag || result == Result.FAIL; } if (flag2) { next(); if (flag) { return Tuple.Create(item1: true, Result.FAIL); } return Tuple.Create(item1: true, Result.DONE); } return Tuple.Create(item1: true, Result.RUN); } return Tuple.Create(item1: false, Result.RUN); } public Tuple Check(T id, Func func) { return Check(Check(Convert.ToInt32(id), func)); } public Tuple Execute(T id, Func func) { return Check(execute(Convert.ToInt32(id), func)); } public Tuple Wait(T id, Func func, double timeout = 2147483647.0) { return Check(wait(Convert.ToInt32(id), func, timeout)); } public Tuple Wait(T id, Func func, double timeout = 2147483647.0) { return Check(wait(Convert.ToInt32(id), func, timeout)); } public Tuple ExecuteAndWait(T id, Func execute, Func check, double timeout = 2147483647.0) { int num = Convert.ToInt32(id); bool flag = Acitve(num); Result? result = Result.RUN; if (flag) { if (state == STATE.IDLE) { if (!execute()) { ExecuteResult = Tuple.Create(flag, Result.FAIL); return Tuple.Create(flag, Result.FAIL); } timer.Start(timeout); state = STATE.WAIT; _currentTokenId = num; } result = check(); if (!result.HasValue) { ExecuteResult = Tuple.Create(flag, Result.FAIL); return Tuple.Create(flag, Result.FAIL); } if (result == Result.DONE) { next(); ExecuteResult = Tuple.Create(item1: true, Result.RUN); return Tuple.Create(item1: true, Result.RUN); } if (result == Result.Succeed) { next(); ExecuteResult = Tuple.Create(item1: true, Result.RUN); return Tuple.Create(item1: true, Result.RUN); } if (result == Result.FAIL) { ExecuteResult = Tuple.Create(item1: true, Result.FAIL); return Tuple.Create(item1: true, Result.FAIL); } if (timer.IsTimeout()) { ExecuteResult = Tuple.Create(item1: true, Result.TIMEOUT); return Tuple.Create(item1: true, Result.TIMEOUT); } ExecuteResult = Tuple.Create(item1: true, Result.RUN); return Tuple.Create(item1: true, Result.RUN); } ExecuteResult = Tuple.Create(item1: false, Result.RUN); return Tuple.Create(item1: false, Result.RUN); } public Tuple Wait(T id, IRoutine rt) { int id2 = Convert.ToInt32(id); if (Acitve(id2)) { if (state == STATE.IDLE) { rt.Start(); state = STATE.WAIT; } Result item = rt.Monitor(); return Tuple.Create(item1: true, item); } return Tuple.Create(item1: false, Result.RUN); } public Tuple Monitor(T id, Func func, Func check, double time) { int id2 = Convert.ToInt32(id); bool flag = Acitve(id2); bool flag2 = false; if (flag) { if (state == STATE.IDLE) { if (func != null && !func()) { return Tuple.Create(item1: true, Result.FAIL); } timer.Start(time); state = STATE.WAIT; } if (!check()) { return Tuple.Create(item1: true, Result.FAIL); } if (timer.IsTimeout()) { next(); } return Tuple.Create(item1: true, Result.RUN); } return Tuple.Create(item1: false, Result.RUN); } public Tuple Delay(T id, Func func, double time) { int num = Convert.ToInt32(id); if (Acitve(num)) { if (state == STATE.IDLE) { if (func != null && !func()) { ExecuteResult = Tuple.Create(item1: true, Result.FAIL); return Tuple.Create(item1: true, Result.FAIL); } _currentTokenId = num; timer.Start(time); state = STATE.WAIT; } if (timer.IsTimeout()) { next(); } ExecuteResult = Tuple.Create(item1: true, Result.RUN); return Tuple.Create(item1: true, Result.RUN); } ExecuteResult = Tuple.Create(item1: false, Result.RUN); return Tuple.Create(item1: false, Result.RUN); } public Tuple DelayCheck(T id, Func func, double time) { int id2 = Convert.ToInt32(id); if (Acitve(id2)) { if (state == STATE.IDLE) { timer.Start(time); state = STATE.WAIT; } if (timer.IsTimeout()) { if (func != null && !func()) { return Tuple.Create(item1: true, Result.FAIL); } next(); } return Tuple.Create(item1: true, Result.RUN); } return Tuple.Create(item1: false, Result.RUN); } private Tuple execute(int id, Func func) { bool flag = Acitve(id); bool flag2 = false; if (flag) { flag2 = func(); if (flag2) { next(); } } return Tuple.Create(flag, flag2); } private Tuple Check(int id, Func func) { bool flag = Acitve(id); bool item = false; if (flag) { if (ExecuteResult.Item1) { return Tuple.Create(item1: true, item2: true); } item = func(); next(); } return Tuple.Create(flag, item); } private Tuple wait(int id, Func func, double timeout = 2147483647.0) { bool flag = Acitve(id); bool flag2 = false; bool item = false; if (flag) { if (state == STATE.IDLE) { timer.Start(timeout); state = STATE.WAIT; } flag2 = func(); if (flag2) { next(); } item = timer.IsTimeout(); } return Tuple.Create(flag, flag2, item); } private Tuple wait(int id, Func func, double timeout = 2147483647.0) { bool flag = Acitve(id); bool? item = false; bool item2 = false; if (flag) { if (state == STATE.IDLE) { timer.Start(timeout); state = STATE.WAIT; } item = func(); if (item.HasValue && item.Value) { next(); } item2 = timer.IsTimeout(); } return Tuple.Create(flag, item, item2); } private Tuple Check(Tuple value) { if (value.Item1) { if (!value.Item2) { ExecuteResult = Tuple.Create(item1: true, Result.FAIL); return Tuple.Create(item1: true, Result.FAIL); } ExecuteResult = Tuple.Create(item1: true, Result.RUN); return Tuple.Create(item1: true, Result.RUN); } ExecuteResult = Tuple.Create(item1: false, Result.RUN); return Tuple.Create(item1: false, Result.RUN); } private Tuple Check(Tuple value) { if (value.Item1) { if (CheckTimeout(value)) { return Tuple.Create(item1: true, Result.TIMEOUT); } return Tuple.Create(item1: true, Result.RUN); } return Tuple.Create(item1: false, Result.RUN); } private Tuple Check(Tuple value) { if (value.Item1) { if (!value.Item2.HasValue) { return Tuple.Create(item1: true, Result.FAIL); } if (value.Item2 == false && value.Item3) { return Tuple.Create(item1: true, Result.TIMEOUT); } return Tuple.Create(item1: true, Result.RUN); } return Tuple.Create(item1: false, Result.RUN); } private bool CheckTimeout(Tuple value) { return value.Item1 && !value.Item2 && value.Item3; } private bool Acitve(int id) { if (_steps.Contains(id)) { return false; } _id = id; return true; } private void next() { _steps.Push(_id); state = STATE.IDLE; } private void next(int step) { while (_steps.Pop() != step) { } state = STATE.IDLE; } public void Delay(int id, double delaySeconds) { Tuple tuple = Delay(id, () => true, delaySeconds * 1000.0); if (tuple.Item1 && tuple.Item2 != 0) { } } public bool IsActived(int id) { return _steps.Contains(id); } public override bool Home(out string reason) { IsHomed = false; reason = ""; bool flag = CheckToPostMessage(0, "Home"); if (!flag) { reason = $"Can't execute on {CurrentState}"; } return flag; } public virtual bool IsCarrierEnabled { get { //debug 完全取决于sc的值 if (SC.ContainsItem($"CarrierInfo.Carrier{InfoPadCarrierIndex}.EnableCarrier")) { //return SC.GetValue($"CarrierInfo.Carrier{InfoPadCarrierIndex}.EnableCarrier"); return true; } return true; } } public override bool IsEnableLoad(out string reason) { if (!_isPlaced) { reason = "No carrier placed"; return false; } if (_isDocked) { reason = "Carrier is docked"; return false; } if (!IsReady()) { reason = "Not Ready"; return false; } if (!IsCarrierEnabled) { reason = "CarrierNotEnabled"; return false; } reason = ""; return true; } public override bool Load(out string reason) { if (!IsEnableLoad(out reason)) { EV.PostAlarmLog("LoadPort", "Can't execute load command due to " + reason); if (reason == "CarrierNotEnabled") { EV.Notify($"{LPModuleName}CarrierNotEnabled"); } return false; } reason = ""; if (!((!IsMapWaferByLoadPort) ? CheckToPostMessage(3, "LoadWithoutMap") : CheckToPostMessage(3, "LoadWithMap"))) { reason = $"Can't execute on {CurrentState}"; return false; } return true; } protected override void SubscribeDataVariable() { Singleton.Instance.SubscribeLocation(LPModuleName, 25); Singleton.Instance.SubscribeLocation(LPModuleName.ToString()); DATA.Subscribe(Name, "IsPresent" , () => _isPresent); DATA.Subscribe(Name, "IsPlaced" , () => _isPlaced); DATA.Subscribe(Name, "IsClamped" , () => ClampState == FoupClampState.Close); DATA.Subscribe(Name, "IsDocked" , () => DockState == FoupDockState.Docked); DATA.Subscribe(Name, "IsDoorOpen" , () => DoorState == FoupDoorState.Open); DATA.Subscribe(Name, "IsAccessSwPressed" , () => IsAccessSwPressed); DATA.Subscribe(Name, "CarrierId" , () => _carrierId); DATA.Subscribe(Name, "LPLotID" , () => _lplotID); DATA.Subscribe(Name, "IsMapped" , () => _isMapped); DATA.Subscribe(Name, "IsAutoDetectCarrierType" , () => IsAutoDetectCarrierType); DATA.Subscribe(Name, "ValidCarrierTypeList" , () => ValidCarrierTypeList); DATA.Subscribe(Name + ".LoadportState" , () => CurrentState.ToString()); //DATA.Subscribe(Name + ".Status" , () => CurrentState.ToString()); DATA.Subscribe(Name + ".LoadportError" , () => ErrorCode); DATA.Subscribe(Name + ".CassetteState" , () => CassetteState); DATA.Subscribe(Name + ".FoupClampState" , () => ClampState); DATA.Subscribe(Name + ".FoupDockState" , () => DockState); DATA.Subscribe(Name + ".FoupDoorState" , () => DoorState); DATA.Subscribe(Name + ".FoupDoorPosition" , () => DoorPosition); DATA.Subscribe(Name + ".SlotMap" , () => SlotMap); DATA.Subscribe(Name + ".WaferMapThickness" , () => WaferMapThickness); DATA.Subscribe(Name + ".IndicatiorLoad" , () => IndicatiorLoad ); DATA.Subscribe(Name + ".IndicatiorUnload" , () => IndicatiorUnload ) ; DATA.Subscribe(Name + ".IndicatiorPresence" , () => IndicatiorPresence ); DATA.Subscribe(Name + ".IndicatiorPlacement" , () => IndicatiorPlacement ); DATA.Subscribe(Name + ".IndicatiorAlarm" , () => IndicatorAlarm ); DATA.Subscribe(Name + ".IndicatiorAccessAuto" , () => IndicatiorAccessAuto ); DATA.Subscribe(Name + ".IndicatiorAccessManual" , () => IndicatiorAccessManual ); DATA.Subscribe(Name + ".IndicatiorOpAccess" , () => IndicatiorOpAccess ); DATA.Subscribe(Name + ".IndicatiorStatus1" , () => IndicatiorStatus1 ); DATA.Subscribe(Name + ".IndicatiorStatus2" , () => IndicatiorStatus2 ); DATA.Subscribe(Name + ".CasstleType" , () => (int)CasstleType ); DATA.Subscribe(Name + ".InfoPadCarrierType" , () => SpecCarrierType ); DATA.Subscribe(Name + ".InfoPadCarrierTypeInformation" , () => SpecCarrierInformation ); DATA.Subscribe(Name + ".InfoPadCarrierIndex" , () => InfoPadCarrierIndex ); DATA.Subscribe(Name + ".CarrierWaferSize" , () => GetCurrentWaferSize().ToString()); DATA.Subscribe(Name + ".IsError" , () => CurrentState == LoadPortStateEnum.Error); DATA.Subscribe(Name + ".PreDefineWaferCount" , () => PreDefineWaferCount); DATA.Subscribe(Name + ".IsVerifyPreDefineWaferCount" , () => IsVerifyPreDefineWaferCount); DATA.Subscribe(Name + ".ValidSlotsNumber" , () => ValidSlotsNumber); } } }