using System.Xml; using Aitex.Core.RT.DataCenter; 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 MECF.Framework.Common.Equipment; using MECF.Framework.Common.SubstrateTrackings; namespace Aitex.Core.RT.Device.Unit { /// /// /// public class IoTurnOver : BaseDevice, IDevice { private readonly DIAccessor _di0Degree; private readonly DIAccessor _di180Degree; private readonly DIAccessor _diAlarm; private readonly DIAccessor _diBusy; private readonly DIAccessor _diGrip; private readonly DIAccessor _diOrigin; private readonly DIAccessor _diPlacement; private readonly DIAccessor _diPressureError; private readonly DIAccessor _diUngrip; private readonly DOAccessor _doGrip; private readonly DOAccessor _doM0; private readonly DOAccessor _doM1; private readonly DOAccessor _doOrigin; private readonly DOAccessor _doResetError; private readonly DOAccessor _doStop; private readonly DOAccessor _doUngrip; //private bool _cmdLoop; //private int _interval; private DeviceTimer _loopTimeout = new DeviceTimer(); private readonly DeviceTimer _loopTimer = new DeviceTimer(); private readonly SCConfigItem _scLoopInterval; //private SCConfigItem _scLoopTimeout; private TurnOverState _state = TurnOverState.Idle; public TurnOverState State => _state; private R_TRIG _trigCloseError = new R_TRIG(); private R_TRIG _trigOpenError = new R_TRIG(); private R_TRIG _trigReset = new R_TRIG(); private R_TRIG _trigSetPointDone = new R_TRIG(); public const string EventWaferTurnOverStart = "WAFER_TURN_OVER_START"; public const string EventWaferTurnOverEnd = "WAFER_TURN_OVER_COMPLETE"; // DI_TurnOverPlacement // DI_TurnOverGrip // DI_TurnOverUngrip // DI_TurnOverBusy // DI_TurnOverPressureError // // DI_TurnOverAlarm // DI_TurnOverOrigin // DI_TurnOver0Degree // DI_TurnOver180Degree // // DO_TurnOverGrip // DO_TurnOverUngrip // DO_TurnOverM0 // DO_TurnOverM1 // DO_TurnOverStop // // DO_TurnOverOrigin // DO_TurnOverResetError public IoTurnOver(string module, XmlElement node, string ioModule = "") { Module = node.GetAttribute("module"); Name = node.GetAttribute("id"); Display = node.GetAttribute("display"); DeviceID = node.GetAttribute("schematicId"); _diPlacement = ParseDiNode("DI_TurnOverPlacement", node, ioModule); _diGrip = ParseDiNode("DI_TurnOverGrip", node, ioModule); _diUngrip = ParseDiNode("DI_TurnOverUngrip", node, ioModule); _diBusy = ParseDiNode("DI_TurnOverBusy", node, ioModule); _diPressureError = ParseDiNode("DI_TurnOverPressureError", node, ioModule); _diAlarm = ParseDiNode("DI_TurnOverAlarm", node, ioModule); _diOrigin = ParseDiNode("DI_TurnOverOrigin", node, ioModule); _di0Degree = ParseDiNode("DI_TurnOver0Degree", node, ioModule); _di180Degree = ParseDiNode("DI_TurnOver180Degree", node, ioModule); _doGrip = ParseDoNode("DO_TurnOverGrip", node, ioModule); _doUngrip = ParseDoNode("DO_TurnOverUngrip", node, ioModule); _doM0 = ParseDoNode("DO_TurnOverM0", node, ioModule); _doM1 = ParseDoNode("DO_TurnOverM1", node, ioModule); _doStop = ParseDoNode("DO_TurnOverStop", node, ioModule); _doOrigin = ParseDoNode("DO_TurnOverOrigin", node, ioModule); _doResetError = ParseDoNode("DO_TurnOverResetError", node, ioModule); _scLoopInterval = SC.GetConfigItem("Turnover.IntervalTimeLimit"); } public int TimelimitAction { get { if (SC.ContainsItem($"Turnover.TimeLimitTurnoverAction")) return SC.GetValue($"Turnover.TimeLimitTurnoverAction"); return 60; } } public bool IsHomed => _diOrigin.Value; public bool IsPlacement => !_diPlacement.Value; public bool IsAlarm => !_diAlarm.Value; public bool IsPressureError => _diPressureError ==null? false: !_diPressureError.Value; public bool IsBusy => _diBusy.Value || _state != TurnOverState.Idle; public bool IsIdle => !_diBusy.Value; public bool IsGrip => _diGrip.Value; public bool IsUnGrip => _diUngrip.Value; public bool Is0Degree => _di0Degree.Value; public bool Is180Degree => _di180Degree.Value; public bool IsEnableWaferTransfer => Is0Degree && !IsBusy && IsUnGrip && !IsAlarm && IsPlacement; public bool Initialize() { DATA.Subscribe($"{Module}.{Name}.State", () => _state.ToString()); DATA.Subscribe($"{Module}.{Name}.IsHomed", () => IsHomed); DATA.Subscribe($"{Module}.{Name}.IsBusy", () => IsBusy); DATA.Subscribe($"{Module}.{Name}.IsGrip", () => IsGrip); DATA.Subscribe($"{Module}.{Name}.IsUnGrip", () => IsUnGrip); DATA.Subscribe($"{Module}.{Name}.Is0Degree", () => Is0Degree); DATA.Subscribe($"{Module}.{Name}.Is180Degree", () => Is180Degree); DATA.Subscribe($"{Module}.{Name}.IsPlacement", () => IsPlacement); DATA.Subscribe($"{Module}.{Name}.IsAlarm", () => IsAlarm); DATA.Subscribe($"{Module}.{Name}.IsPressureError", () => IsPressureError); DATA.Subscribe($"{Module}.{Name}.GripCmd", () => _doGrip.Value); DATA.Subscribe($"{Module}.{Name}.TurnTo0Cmd", () => _doM0.Value); DATA.Subscribe($"{Module}.{Name}.TurnTo180Cmd", () => _doM1.Value); DATA.Subscribe($"{Module}.{Name}.HomeCmd", () => _doOrigin.Value); DATA.Subscribe($"{Module}.{Name}.ResetCmd", () => _doResetError.Value); DATA.Subscribe($"{Module}.{Name}.StopCmd", () => _doStop==null?false: _doStop.Value); DATA.Subscribe($"{Module}.{Name}.UnGripCmd", () => _doUngrip.Value); EV.Subscribe(new EventItem("Event", EventWaferTurnOverStart, "Start Turn Over")); EV.Subscribe(new EventItem("Event", EventWaferTurnOverEnd, "Turn Over End")); //System.TurnoverStation. OP.Subscribe($"{Module}.{Name}.Home", (cmd, param) => { if (!Home(out var reason)) { EV.PostWarningLog(Module, $"{Name} can not home, {reason}"); return false; } return true; }); OP.Subscribe($"{Module}.{Name}.Grip", (cmd, param) => { if (!Grip(out var reason)) { EV.PostWarningLog(Module, $"{Name} can not grip, {reason}"); return false; } return true; }); OP.Subscribe($"{Module}.{Name}.Ungrip", (cmd, param) => { if (!UnGrip(out var reason)) { EV.PostWarningLog(Module, $"{Name} can not ungrip, {reason}"); return false; } return true; }); OP.Subscribe($"{Module}.{Name}.TurnTo0", (cmd, param) => { if (!TurnTo0(out var reason)) { EV.PostWarningLog(Module, $"{Name} can not turn to 0 degree, {reason}"); return false; } return true; }); OP.Subscribe($"{Module}.{Name}.TurnTo180", (cmd, param) => { if (!TurnTo180(out var reason)) { EV.PostWarningLog(Module, $"{Name} can not turn to 180 degree, {reason}"); return false; } return true; }); OP.Subscribe($"{Module}.{Name}.Stop", (cmd, param) => { if (!Stop(out var reason)) { EV.PostWarningLog(Module, $"{Name} can not turn to 180 degree, {reason}"); return false; } return true; }); return true; } public void Terminate() { } public void Monitor() { if (IsAlarm || IsPressureError) { _state = TurnOverState.Error; _doGrip.SetValue(false, out _); _doM0.SetValue(false, out _); _doM1.SetValue(false, out _); _doOrigin.SetValue(false, out _); if(_doStop !=null) _doStop.SetValue(false, out _); _doUngrip.SetValue(false, out _); return; } switch (_state) { case TurnOverState.OnHoming: _doM0.SetValue(false, out _); _doM1.SetValue(false, out _); _doOrigin.SetValue(true, out _); if (IsHomed) { if (!_doOrigin.SetValue(false, out var reason)) LOG.Error($"{Module} reset DO failed, {reason}"); _state = TurnOverState.Idle; } else if (_loopTimer.IsTimeout()) { if (!_doOrigin.SetValue(false, out var reason)) LOG.Error($"{Module} reset DO failed, {reason}"); EV.PostAlarmLog(Module, $"{Module} {Name} Can not Home in {_scLoopInterval.IntValue} seconds"); _state = TurnOverState.Error; } break; case TurnOverState.OnGripping: if (IsGrip) { //if (!_doGrip.SetValue(false, out var reason)) LOG.Error($"{Module} reset DO failed, {reason}"); _state = TurnOverState.Idle; } else if (_loopTimer.IsTimeout()) { //if (!_doOrigin.SetValue(false, out var reason)) // LOG.Error($"{Module} reset DO failed, {reason}"); EV.PostAlarmLog(Module, $"{Module} {Name} Can not Grip in {_scLoopInterval.IntValue} seconds"); _state = TurnOverState.Error; } break; case TurnOverState.OnUnGripping: if (IsUnGrip) { //if (!_doUngrip.SetValue(false, out var reason)) // LOG.Error($"{Module} reset DO failed, {reason}"); _state = TurnOverState.Idle; } else if (_loopTimer.IsTimeout()) { //if (!_doUngrip.SetValue(false, out var reason)) // LOG.Error($"{Module} reset DO failed, {reason}"); EV.PostAlarmLog(Module, $"{Module} {Name} Can not UnGrip in {_scLoopInterval.IntValue} seconds"); _state = TurnOverState.Error; } break; case TurnOverState.OnTurningTo0: if (_doM1.Value == true) _doM1.SetValue(false, out _); if (_doM0.Value == false) _doM0.SetValue(true, out _); if (Is0Degree && !_diBusy.Value) { if (!_doM0.SetValue(false, out var reason)) LOG.Error($"{Module} reset DO failed, {reason}"); _state = TurnOverState.Idle; } else if (_loopTimer.IsTimeout()) { ////if (!_doM0.SetValue(false, out var reason)) // LOG.Error($"{Module} reset DO failed, {reason}"); EV.PostAlarmLog(Module, $"{Module} {Name} Can not Turn to 0 in {_scLoopInterval.IntValue} seconds"); _state = TurnOverState.Error; } break; case TurnOverState.OnTurningTo180: if(_doM1.Value == false) _doM1.SetValue(true, out _); if (_doM0.Value == true) _doM0.SetValue(false, out _); if (Is180Degree &&!_diBusy.Value) { if (!_doM1.SetValue(false, out var reason)) LOG.Error($"{Module} reset DO failed, {reason}"); _state = TurnOverState.Idle; var wafer = WaferManager.Instance.GetWafer(ModuleName.TurnOverStation, 0); if (!wafer.IsWaferEmpty) { var dvid = new SerializableDictionary() { {"LOT_ID", wafer.LotId}, {"WAFER_ID", wafer.WaferID}, {"ARRIVE_POS_NAME", "TRN1"}, }; EV.Notify(EventWaferTurnOverEnd, dvid); } } else if (_loopTimer.IsTimeout()) { //if (!_doM1.SetValue(false, out var reason)) LOG.Error($"{Module} reset DO failed, {reason}"); EV.PostAlarmLog(Module, $"{Module} {Name} Can not Turn to 180 in {_scLoopInterval.IntValue} seconds"); _state = TurnOverState.Error; } break; case TurnOverState.OnErrorCleaning: if (!IsAlarm) { if (!_doResetError.SetValue(false, out var reason)) LOG.Error($"{Module} reset DO failed, {reason}"); _state = TurnOverState.Idle; } break; case TurnOverState.Stopping: if (!IsBusy) { if (_doStop != null) { if (!_doStop.SetValue(false, out var reason)) LOG.Error($"{Module} reset DO failed, {reason}"); } _state = TurnOverState.Stop; } break; default: //if (!_diBusy.Value && !_doStop.Value) _state = DeviceState.Idle; break; } } public void Reset() { _doGrip.SetValue(false, out _); _doM0.SetValue(false, out _); _doM1.SetValue(false, out _); _doOrigin.SetValue(false, out _); if(_doStop!=null) _doStop.SetValue(false, out _); _doUngrip.SetValue(false, out _); ResetError(out _); } public bool Home(out string reason) { reason = string.Empty; EV.PostInfoLog(Module, $"{Module}.{Name} Home"); //if (IsPressureError) //{ // reason = "Turn over station pressure error"; // return false; //} _doM0.SetValue(false, out _); _doM1.SetValue(false, out _); _doOrigin.SetValue(true, out _); _state = TurnOverState.OnHoming; _loopTimer.Start(_scLoopInterval.IntValue * 1000); return true; } public bool Grip(out string reason) { reason = string.Empty; EV.PostInfoLog(Module, $"{Module}.{Name} Grip"); if (IsPressureError) { reason = "Turn over station pressure error"; EV.PostAlarmLog(Module, $"{Module}.{Name} pressure error."); return false; } //if (_doGrip.Value) //{ // reason = "Gripping, can't do again"; // EV.PostAlarmLog(Module, $"{Module}.{Name} {reason}."); // return false; //} _doUngrip.SetValue(false, out _); _doGrip.SetValue(true, out _); _state = TurnOverState.OnGripping; _loopTimer.Start(_scLoopInterval.IntValue * 1000); return true; } public bool UnGrip(out string reason) { reason = string.Empty; EV.PostInfoLog(Module, $"{Module}.{Name} UnGrip"); if (IsPressureError) { reason = "Turn over station pressure error"; return false; } //if (_doUngrip.Value) //{ // reason = "UnGripping, can't do again"; // return false; //} _doGrip.SetValue(false, out _); _doUngrip.SetValue(true, out _); _state = TurnOverState.OnUnGripping; _loopTimer.Start(_scLoopInterval.IntValue * 1000); return true; } public bool TurnTo0(out string reason) { reason = string.Empty; EV.PostInfoLog(Module, $"{Module}.{Name} Turn to 0"); //if (IsPressureError) //{ // reason = "Turn over station pressure error"; // return false; //} //if (_doM0.Value) //{ // reason = "Turning, can't do again"; // return false; //} _state = TurnOverState.OnTurningTo0; //if (_doM1.Value == true) _doM1.SetValue(false, out _); //if (_doM0.Value == false) _doM0.SetValue(true, out _); _loopTimer.Start(_scLoopInterval.IntValue * 1000); return true; } public bool TurnTo180(out string reason) { reason = string.Empty; EV.PostInfoLog(Module, $"{Module}.{Name} Turn to 180"); //if (IsPressureError) //{ // reason = "Turn over station pressure error"; // return false; //} //if (_doM1.Value) //{ // reason = "Turning, can't do again"; // return false; //} _state = TurnOverState.OnTurningTo180; //if (_doM0.Value == true) _doM0.SetValue(false, out _); //if (_doM1.Value == false) _doM1.SetValue(true, out _); _loopTimer.Start(_scLoopInterval.IntValue * 1000); var wafer = WaferManager.Instance.GetWafer(ModuleName.TurnOverStation,0); if (!wafer.IsWaferEmpty) { var dvid = new SerializableDictionary() { {"LOT_ID", wafer.LotId}, {"WAFER_ID", wafer.WaferID}, {"ARRIVE_POS_NAME", "TRN1"} }; EV.Notify(EventWaferTurnOverStart, dvid); } return true; } public bool Stop(out string reason) { reason = string.Empty; EV.PostInfoLog(Module, $"{Module}.{Name} Stop"); if (_doStop != null) { if (_doStop.Value) { reason = "Stopping, can't do again"; return false; } _doStop.SetValue(true, out _); } _state = TurnOverState.Stopping; _loopTimer.Start(_scLoopInterval.IntValue * 1000); return true; } private bool ResetError(out string reason) { reason = string.Empty; //EV.PostInfoLog(Module, $"{Module}.{Name} Reset Error"); if (_doResetError.Value) return true; _doResetError.SetValue(true, out _); _state = TurnOverState.OnErrorCleaning; _loopTimer.Start(_scLoopInterval.IntValue * 1000); return true; } } public enum TurnOverState { Idle, OnHoming, OnTurningTo0, OnTurningTo180, OnGripping, OnUnGripping, Error, OnErrorCleaning, Stopping, Stop } }