using System; 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; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Flipper.FlipperBase; namespace Aitex.Core.RT.Device.Unit { /// /// /// public class IoTurnOver : FlipperBaseDevice { 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 DateTime _dtActionStart; //private DeviceTimer _loopTimeout = new DeviceTimer(); //private readonly DeviceTimer _loopTimer = new DeviceTimer(); //private readonly SCConfigItem _scLoopInterval; //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(); // 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 string Display, DeviceID; private PeriodicJob _thread; public IoTurnOver(string module, XmlElement node, string ioModule = ""):base(node.GetAttribute("module"), node.GetAttribute("id")) { 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"); InitializeIoTurnover(); } public override bool IsPlacement { get { if(_diPlacement !=null) return !_diPlacement.Value; return WaferManager.Instance.CheckHasWafer(ModuleName.TurnOverStation, 0); } } public bool IsAlarm => !_diAlarm.Value; public bool IsPressureError => _diPressureError ==null? false: !_diPressureError.Value; public override FlipperPosEnum CurrentFlipperPosition { get { if (_di0Degree.Value && !_di180Degree.Value) return FlipperPosEnum.FrontSide; if (!_di0Degree.Value && _di180Degree.Value) return FlipperPosEnum.BackSide; return FlipperPosEnum.Unknow; } } public override GripPosEnum CurrentGripperPositon { get { if (_diGrip.Value && !_diUngrip.Value) return GripPosEnum.Close; if (!_diGrip.Value && _diUngrip.Value) return GripPosEnum.Open; return GripPosEnum.Unknow; } } //public bool IsBusy => _diBusy.Value || _state != TurnOverState.Idle; //public bool IsIdle => !_diBusy.Value && _state == TurnOverState.Idle; //public bool IsGrip => _diGrip.Value && !_diUngrip.Value; //public bool IsUnGrip => _diUngrip.Value && !_diGrip.Value; //public bool Is0Degree => _di0Degree.Value &&!_di180Degree.Value; //public bool Is180Degree => _di180Degree.Value&&!_di0Degree.Value; //public bool IsEnableWaferTransfer => Is0Degree && !IsBusy && IsUnGrip && !IsAlarm && // IsPlacement; public bool InitializeIoTurnover() { //DATA.Subscribe($"{Module}.{Name}.State", () => _state.ToString()); DATA.Subscribe($"{Module}.{Name}.IsHomed", () => _diOrigin.Value); DATA.Subscribe($"{Module}.{Name}.IsBusy", () => _diBusy.Value); DATA.Subscribe($"{Module}.{Name}.IsGrip", () => _diGrip.Value); DATA.Subscribe($"{Module}.{Name}.IsUnGrip", () => _diUngrip.Value); DATA.Subscribe($"{Module}.{Name}.Is0Degree", () => _di0Degree.Value); DATA.Subscribe($"{Module}.{Name}.Is180Degree", () => _di180Degree.Value); DATA.Subscribe($"{Module}.{Name}.IsPlacement", () => IsPlacement); DATA.Subscribe($"{Module}.{Name}.IsAlarm", () => _diAlarm.Value); DATA.Subscribe($"{Module}.{Name}.IsPressureError", () => _diPressureError==null?false: _diPressureError.Value); 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); _trigError = new R_TRIG(); _thread = new PeriodicJob(50, OnTimerMonitor, $"{Module}.{Name} MonitorHandler", true); return true; } private R_TRIG _trigError; private bool OnTimerMonitor() { _trigError.CLK = (_diAlarm != null && !_diAlarm.Value) || (_diPressureError != null && !_diPressureError.Value); if(_trigError.Q) { OnError($"{FlipperModuleName}Error"); } return true; } public override 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)// && _di0Degree.Value) // { // 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.IsEmpty) // { // 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 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.IsEmpty) // { // 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 DOAccessor ParseDoNode(string name, XmlElement node, string ioModule = "") { if (!string.IsNullOrEmpty(node.GetAttribute(name).Trim())) return IO.DO[string.IsNullOrEmpty(ioModule) ? node.GetAttribute(name).Trim() : $"{ioModule}.{node.GetAttribute(name).Trim()}"]; return null; } public DIAccessor ParseDiNode(string name, XmlElement node, string ioModule = "") { if (!string.IsNullOrEmpty(node.GetAttribute(name).Trim())) return IO.DI[string.IsNullOrEmpty(ioModule) ? node.GetAttribute(name).Trim() : $"{ioModule}.{node.GetAttribute(name).Trim()}"]; return null; } protected override bool fStartGrip(object[] param) { _doGrip.SetValue(true, out _); _doUngrip.SetValue(false, out _); _dtActionStart = DateTime.Now; return true; } protected override bool fMonitorGrip(object[] param) { IsBusy = false; if (DateTime.Now - _dtActionStart > TimeSpan.FromSeconds(TimelimitAction)) { OnError("Grip timeout"); return false; } if (_diGrip.Value && !_diUngrip.Value && !_diBusy.Value) { EV.PostInfoLog("Flipper", $"{FlipperModuleName} grip completed"); return true; } return false; } protected override bool fStartUnGrip(object[] param) { _doGrip.SetValue(false, out _); _doUngrip.SetValue(true, out _); _dtActionStart = DateTime.Now; return true; } protected override bool fMonitorUnGrip(object[] param) { IsBusy = false; if (DateTime.Now - _dtActionStart > TimeSpan.FromSeconds(TimelimitAction)) { OnError("UnGrip timeout"); return false; } if (!_diGrip.Value && _diUngrip.Value && !_diBusy.Value) { EV.PostInfoLog("Flipper", $"{FlipperModuleName} ungrip completed"); return true; } return false; } protected override bool fStartHome(object[] param) { _doM0.SetValue(false, out _); _doM1.SetValue(false, out _); _doOrigin.SetValue(true, out _); _dtActionStart = DateTime.Now; _dtActionStart = DateTime.Now; return true; } protected override bool fMonitorHome(object[] param) { IsBusy = false; if (DateTime.Now - _dtActionStart > TimeSpan.FromSeconds(TimelimitAction)) { OnError("Home timeout"); _doM1.SetValue(false, out _); _doM0.SetValue(false, out _); _doOrigin.SetValue(false, out _); return false; } if (_diOrigin.Value && !_diBusy.Value) { _doOrigin.SetValue(false, out _); EV.PostInfoLog("Flipper", $"{FlipperModuleName} home completed"); _doM1.SetValue(false, out _); _doM0.SetValue(false, out _); _doOrigin.SetValue(false, out _); return true; } return false; } protected override bool fStartTurnTo0(object[] param) { _doM0.SetValue(true, out _); _doM1.SetValue(false, out _); _dtActionStart = DateTime.Now; var wafer = WaferManager.Instance.GetWafer(ModuleName.TurnOverStation, 0); if (!wafer.IsEmpty) { var dvid = new SerializableDictionary() { {"LOT_ID", wafer.LotId}, {"WAFER_ID", wafer.WaferID}, {"ARRIVE_POS_NAME", FlipperModuleName.ToString()} }; EV.Notify(EventWaferTurnOverStart, dvid); } return true; } protected override bool fMonitorTurnTo0(object[] param) { IsBusy = false; if (DateTime.Now - _dtActionStart > TimeSpan.FromSeconds(TimelimitAction)) { OnError("Turn to 0 timeout"); _doM1.SetValue(false, out _); _doM0.SetValue(false, out _); _doOrigin.SetValue(false, out _); return false; } if (_di0Degree.Value && !_di180Degree.Value && !_diBusy.Value) { EV.PostInfoLog("Flipper", $"{FlipperModuleName} turn to 0 degree completed"); var wafer = WaferManager.Instance.GetWafer(ModuleName.TurnOverStation, 0); if (!wafer.IsEmpty) { var dvid = new SerializableDictionary() { {"LOT_ID", wafer.LotId}, {"WAFER_ID", wafer.WaferID}, {"ARRIVE_POS_NAME", FlipperModuleName.ToString()} }; EV.Notify(EventWaferTurnOverStart, dvid); } _doM1.SetValue(false, out _); _doM0.SetValue(false, out _); _doOrigin.SetValue(false, out _); return true; } return false; } protected override bool fStartTurnTo180(object[] param) { _doM0.SetValue(false, out _); _doM1.SetValue(true, out _); _dtActionStart = DateTime.Now; var wafer = WaferManager.Instance.GetWafer(ModuleName.TurnOverStation, 0); if (!wafer.IsEmpty) { var dvid = new SerializableDictionary() { {"LOT_ID", wafer.LotId}, {"WAFER_ID", wafer.WaferID}, {"ARRIVE_POS_NAME", "TRN1"} }; EV.Notify(EventWaferTurnOverStart, dvid); } return true; } protected override bool fMonitorTurnTo180(object[] param) { IsBusy = false; if (DateTime.Now - _dtActionStart > TimeSpan.FromSeconds(TimelimitAction)) { OnError("Turn to 180 timeout"); _doM1.SetValue(false, out _); _doM0.SetValue(false, out _); _doOrigin.SetValue(false, out _); return false; } if (!_di0Degree.Value && _di180Degree.Value && !_diBusy.Value) { EV.PostInfoLog("Flipper", $"{FlipperModuleName} turn to 180 degree completed"); var wafer = WaferManager.Instance.GetWafer(ModuleName.TurnOverStation, 0); if (!wafer.IsEmpty) { var dvid = new SerializableDictionary() { {"LOT_ID", wafer.LotId}, {"WAFER_ID", wafer.WaferID}, {"ARRIVE_POS_NAME", FlipperModuleName.ToString()} }; EV.Notify(EventWaferTurnOverStart, dvid); } _doM1.SetValue(false, out _); _doM0.SetValue(false, out _); _doOrigin.SetValue(false, out _); return true; } return false; } protected override bool fStartAbort(object[] param) { _doStop.SetValue(true, out _); _doResetError.SetValue(false, out _); _doM0.SetValue(false, out _); _doM1.SetValue(false, out _); IsBusy = false; return true; } protected override bool fStartReset(object[] param) { _doM0.SetValue(false, out _); _doM1.SetValue(false, out _); _doOrigin.SetValue(false, out _); _doStop.SetValue(false, out _); _doResetError.SetValue(true, out _); _dtActionStart = DateTime.Now; return true; } protected override bool fMonitorReset(object[] param) { IsBusy = false; if (DateTime.Now - _dtActionStart > TimeSpan.FromSeconds(TimelimitAction)) { OnError("Reset timeout"); _doResetError.SetValue(false, out _); return false; } if (_diAlarm != null && !_diAlarm.Value) return false; EV.PostInfoLog("Flipper", $"{FlipperModuleName} reset completed"); _doResetError.SetValue(false, out _); return true; } } public enum TurnOverState { Idle, OnHoming, OnTurningTo0, OnTurningTo180, OnGripping, OnUnGripping, Error, OnErrorCleaning, Stopping, Stop } }