using Aitex.Core.RT.Fsm; using Aitex.Core.RT.Log; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using MECF.Framework.Common.CommonData; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.Schedulers; using MECF.Framework.Common.SubstrateTrackings; using CyberX8_Core; using CyberX8_RT.Modules; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CyberX8_RT.Schedulers.EfemRobot { class SchedulerItem { public EfemEntity.MSG MoveType { get; set; } public ModuleName target { get; set; } public Queue moveList { get; set; } public RState Status { get; set; } } public class SchedulerEfemRobot : SchedulerModule { public override bool IsAvailable { get { return _entity.IsIdle && (_entity.IsOnline || !Singleton.Instance.IsAutoMode) && CheckTaskDone() && RunSchedulers(); } } public override bool IsOnline { get { return _entity.IsOnline; } } public override bool IsError { get { return _entity.IsError; } } public override bool IsIdle { get { return _entity.IsIdle; } } public RState RobotStatus { get { return _entity.RobotStatus; } } private EfemEntity _entity = null; private SchedulerItem _currentScheduler = null; private int _entityTaskToken = (int)FSM_MSG.NONE; private int _alignAngle = 0; private int _increasingAngle = 0; public ModuleName PreviousTarget { get; set; } public SchedulerEfemRobot() : base(ModuleName.EfemRobot.ToString()) { _entity = Singleton.Instance.EFEM; PreviousTarget = ModuleName.System; _alignAngle = SC.GetValue($"EFEM.Aligner.AlignAngle"); _increasingAngle = SC.GetValue($"EFEM.Aligner.IncreasingAngle"); } public bool Goto(ModuleName target, int slot) { _entityTaskToken = _entity.InvokeGoto(target, slot); PreviousTarget = target; LogTaskStart(_task, $"Robot goto {target}.{slot + 1}"); return true; } public bool Map(ModuleName destination) { _entityTaskToken = _entity.InvokeMap(destination.ToString()); LogTaskStart(_task, $"{Module} mapping"); PreviousTarget = destination; return true; } public bool Monitor() { return true; } public bool CheckTaskDone() { bool ret = false; switch (_entityTaskToken) { case (int)FSM_MSG.NONE: ret = true; break; case (int)EfemEntity.MSG.Pick: case (int)EfemEntity.MSG.Place: case (int)EfemEntity.MSG.Swap: ret = IsAllWafersArrived(); break; case (int)EfemEntity.MSG.Map: ret = _entity.CheckAcked(_entityTaskToken) && _entity.IsIdle; break; case (int)EfemEntity.MSG.Goto: ret = _entity.CheckAcked(_entityTaskToken) && _entity.IsIdle; break; case (int)EfemEntity.MSG.Align: ret = _entity.CheckAcked(_entityTaskToken) && _entity.IsIdle; break; } if (ret && _task != TaskType.None) { LogTaskDone(_task, ""); _task = TaskType.None; } return ret; } public bool PostMoveItems(MoveItem[] items) { if (items.Length > 0) { _currentScheduler = new SchedulerItem(); _currentScheduler.moveList = new Queue(); _currentScheduler.Status = RState.Init; foreach (var item in items) { LOG.Write(eEvent.EV_ROUTER, ModuleName.EfemRobot, $"Post Moving Item: {item.SourceModule} Slot {item.SourceSlot + 1} => {item.DestinationModule} Slot {item.DestinationSlot + 1}"); _currentScheduler.MoveType = items.First().TransferType == EnumMoveType.Pick ? EfemEntity.MSG.Pick : EfemEntity.MSG.Place; _currentScheduler.target = item.Module; _currentScheduler.moveList.Enqueue(item); } } RunSchedulers(); return true; } bool RunSchedulers() { if (_currentScheduler == null) return true; if (_entity.IsIdle) { if (_currentScheduler.Status == RState.Init) { foreach (var item in _currentScheduler.moveList) { LOG.Write(eEvent.EV_EFEM_ROBOT, ModuleName.EfemRobot, $"EFEM Robot Moving Items: {item.SourceModule} Slot {item.SourceSlot + 1} => {item.DestinationModule} Slot {item.DestinationSlot + 1}"); } if (_entity.CheckToPostMessage((int)_currentScheduler.MoveType, _currentScheduler.moveList)) { _currentScheduler.Status = RState.Running; _entityTaskToken = (int)_currentScheduler.MoveType; } else _entityTaskToken = (int)FSM_MSG.NONE; } else if (_currentScheduler.Status == RState.Running) { if (IsAllWafersArrived()) { if (_entityTaskToken == (int)EfemEntity.MSG.Pick || _entityTaskToken == (int)EfemEntity.MSG.Place || _entityTaskToken == (int)EfemEntity.MSG.Swap) { _entityTaskToken = (int)FSM_MSG.NONE; } _currentScheduler.Status = RState.End; } } } return _currentScheduler.Status == RState.End; } private bool IsAllWafersArrived() { foreach (var item in _currentScheduler.moveList) { if (WaferManager.Instance.CheckNoWafer(item.DestinationModule, item.DestinationSlot)) return false; } return true; } public override void ResetTask() { base.ResetTask(); _entityTaskToken = (int)FSM_MSG.NONE; if (_currentScheduler != null) { _alignAngle = SC.GetValue($"EFEM.Aligner.AlignAngle"); _increasingAngle = SC.GetValue($"EFEM.Aligner.IncreasingAngle"); _currentScheduler.moveList.Clear(); _currentScheduler.Status = RState.End; } } public override bool Align(float angle) { _task = TaskType.Align; LogTaskStart(_task, $"Aligning"); _increasingAngle = SC.GetValue($"EFEM.Aligner.IncreasingAngle"); if (_increasingAngle == 0) { // enable change align angle only with increasing function disable to avoid logic confuse _alignAngle = SC.GetValue($"EFEM.Aligner.AlignAngle"); } _alignAngle = (_alignAngle + _increasingAngle) % 360; _entityTaskToken = _entity.InvokeAlign(ModuleName.Aligner1.ToString(), 0, _alignAngle); return _entityTaskToken == (int)EfemEntity.MSG.Align; } } }