using System; using System.Collections.Generic; using System.Threading.Tasks; using Aitex.Common.Util; using Aitex.Core.RT.Log; using Aitex.Core.Util; using FabConnect.SecsGemInterface.Common; using FabConnect.SecsGemInterface.Common.ToolModel; using FabConnect.SecsGemInterface.GemModel; using Virgo_DCommon; namespace Virgo_DRT.HostWrapper { public class FaHost : IFaHost { public string FaCommunicationState { get { return _gem.CommunicationState.ToString(); } } public string FaControlState { get { return _gem.ControlState.ToString(); } } public string FaControlSubState { get { return _gem.ControlRemoteSwitch.ToString(); } } public bool IsConnected { get { return _gem.IsConnected; } } public int SpoolingState { get { return (int)_gem.SpoolingState; } } public string SpoolingActual { get { return _gem.GetAttribute(GEMVariables.SpoolCountActual, AttributeType.SV) ; } } public string SpoolingTotal { get { return _gem.GetAttribute(GEMVariables.SpoolCountTotal, AttributeType.SV); } } public string SpoolingFullTime { get { return _gem.GetAttribute(GEMVariables.SpoolFullTime, AttributeType.SV); } } public string SpoolingStartTime { get { return _gem.GetAttribute(GEMVariables.SpoolStartTime, AttributeType.SV); } } public bool IsSpoolingEnable { get { return Convert.ToBoolean(_gem.GetAttribute(GEMVariables.SpoolEnabled, AttributeType.EC)); } } private readonly GEMController _gem = new GEMController(); public IHostCallback _equipment; private HashSet _systemBuildInEc = new HashSet(); private HashSet _systemBuildInVariables = new HashSet(); private PeriodicJob _faMonitorThread; private FixSizeQueue _lstEvent = new FixSizeQueue(300); FALogFileCleaner _logCleaner = new FALogFileCleaner(); public void Initialize(IHostCallback equipment, string modelFile) { _equipment = equipment; _gem.CommunicationStateChanged += OnCommunicationStateChanged; _gem.RemoteCommandS2F41In += _gem_RemoteCommandS2F41In; ; _gem.RemoteCommandS2F49In += _gem_RemoteCommandS2F49In; ; _gem.ControlStateChanged += _gem_ControlStateChanged; _gem.ShowTrialMessageBox = false; _gem.Initialize(modelFile, PathManager.GetLogDir()); //get system build in ec _systemBuildInEc = new HashSet(); _systemBuildInEc.Add("EstablishCommunicationsTimeout"); _systemBuildInEc.Add("MaxSpoolTransmit"); _systemBuildInEc.Add("OverWriteSpool"); _systemBuildInEc.Add("MaxSpoolCapacity"); _systemBuildInEc.Add("SpoolEnabled"); _systemBuildInEc.Add("TimeFormat"); //initial system build in variable _systemBuildInVariables.Add("AlarmsEnabled"); _systemBuildInVariables.Add("AlarmsSet"); _systemBuildInVariables.Add("Clock"); _systemBuildInVariables.Add("ControlState"); _systemBuildInVariables.Add("EventsEnabled"); _systemBuildInVariables.Add("PPExecName"); _systemBuildInVariables.Add("PreviousProcessState"); _systemBuildInVariables.Add("ProcessState"); _systemBuildInVariables.Add("SpoolCountActual"); _systemBuildInVariables.Add("SpoolCountTotal"); _systemBuildInVariables.Add("SpoolFullTime"); _systemBuildInVariables.Add("SpoolStartTime"); _systemBuildInVariables.Add("SpoolState"); _systemBuildInVariables.Add("SpoolSubstate"); _logCleaner.Run(); _faMonitorThread = new PeriodicJob(200, MonitorFaTask, "Monitor FA Thread", true); } private void _gem_ControlStateChanged(object sender, SECsEventArgs e) { if (_gem.ControlState == ControlState.OnlineLocal) { _gem.SetRemote(); } } public void Invoke(string method, object[] args) { switch (method) { case FACommandName.FAEnable: _gem.SetEnable(); break; case FACommandName.FADisable: _gem.SetDisable(); break; case FACommandName.FAOnline: _gem.SetOnline(); break; case FACommandName.FAOffline: _gem.SetOffline(); break; case FACommandName.FALocal: _gem.SetLocal(); break; case FACommandName.FARemote: _gem.SetRemote(); break; case FACommandName.FAEnableSpooling: SetEnableSpooling(); break; case FACommandName.FADisableSpooling: SetDisableSpooling(); break; } } private bool _gem_RemoteCommandS2F41In(SECsTransaction trans) { try { bool ret = true; string reason = string.Empty; SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(2, 42, false); string remoteCommandName = trans.Primary.DataItem[0][0].ToString(); switch (remoteCommandName) { case "ScanSlot": { if (trans.Primary.DataItem[0][1][0][0].ToString() != "PORT_ID" ) throw new Exception("ScanSlot Command Format Not Correct"); string portId = trans.Primary.DataItem[0][1][0][1].ToString(); ret = _equipment.ScanSlot(portId, out reason); } break; } reply.DataItem.AddList(); if (ret) { reply.DataItem[0].Add("HCACK", 0, SECsFormat.Binary); } else { reply.DataItem[0].Add("HCACK", 3, SECsFormat.Binary); reply.DataItem[0].Add("CPVALUE", reason, SECsFormat.Ascii); } _gem.SendReply(reply, trans.Id); } catch (Exception ex) { LOG.Write(string.Format("Handle_S2F41 Exception: {0}", ex.Message)); SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(2, 42, false); reply.DataItem.AddList(); reply.DataItem[0].Add("HCACK", 3/*At least one parameter is invalid*/, SECsFormat.Binary); reply.DataItem[0].AddList(); reply.DataItem[0][1].AddList(); reply.DataItem[0][1].Add("CPVALUE", ex.Message, SECsFormat.Ascii); _gem.SendReply(reply, trans.Id); } return true; } private bool _gem_RemoteCommandS2F49In(SECsTransaction trans) { try { bool ret = true; string reason = string.Empty; SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(2, 50, false); string remoteCommandName = trans.Primary.DataItem[0][2].ToString(); switch (remoteCommandName.ToUpper()) { case "START-TRANSFER": { if (trans.Primary.DataItem[0][3][0][0].ToString() != "TRANS_MODE" || trans.Primary.DataItem[0][3][1][0].ToString() != "CAR_ID" || trans.Primary.DataItem[0][3][2][0].ToString() != "LOT_ID" || trans.Primary.DataItem[0][3][3][0].ToString() != "SRC_PORT_ID" || trans.Primary.DataItem[0][3][4][0].ToString() != "WAF_CNT" || trans.Primary.DataItem[0][3][5][0].ToString() != "EXIST_FLAG" || trans.Primary.DataItem[0][3][6][0].ToString() != "WAFER_ID" || trans.Primary.DataItem[0][3][7][0].ToString() != "LASERMARK1" || trans.Primary.DataItem[0][3][8][0].ToString() != "LASERMARK2" || trans.Primary.DataItem[0][3][9][0].ToString() != "TRANS_FLAG" || trans.Primary.DataItem[0][3][10][0].ToString() != "DEST_PORT_ID" || trans.Primary.DataItem[0][3][11][0].ToString() != "DEST_SLOT_NO" || trans.Primary.DataItem[0][3][12][0].ToString() != "DEST_PORT_CTGRY" ) throw new Exception("START-TRANSFER Command Format Not Correct"); //HostRecipe recipe = new HostRecipe(); //ret = _equipment.StartTransfer(recipe, out reason); } break; case "PP-SELECT": { if (trans.Primary.DataItem[0][3][0][0].ToString() != "RECIPE_ID" || trans.Primary.DataItem[0][3][0][1].ToString() != "HostRecipe" ) throw new Exception("PP-SELECT Command Format Not Correct"); string recipeId = trans.Primary.DataItem[0][3][0][1].ToString(); ret = _equipment.PPSelect(recipeId, out reason); } break; } reply.DataItem.AddList(); if (ret) { reply.DataItem[0].Add("HCACK", 0, SECsFormat.Binary); } else { reply.DataItem[0].Add("HCACK", 3, SECsFormat.Binary); reply.DataItem[0].Add("CPVALUE", reason, SECsFormat.Ascii); } _gem.SendReply(reply, trans.Id); } catch (Exception ex) { //WriteLog(string.Format("Handle_S2F49 Exception: {0}", ex.Message)); SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(2, 50, false); reply.DataItem.AddList(); reply.DataItem[0].Add("HCACK", 3/*At least one parameter is invalid*/, SECsFormat.Binary); reply.DataItem[0].AddList(); reply.DataItem[0][1].AddList(); reply.DataItem[0][1].Add("CPVALUE", ex.Message, SECsFormat.Ascii); _gem.SendReply(reply, trans.Id); } return true; } public void Terminate() { _faMonitorThread.Stop(); _logCleaner.Stop(); } public void Enable() { _gem.SetEnable(); } public void Disable() { _gem.SetDisable(); } public void NotifyEvent(string eventName, Dictionary dvid) { _lstEvent.Enqueue(new FaEventItem(){dvid = dvid,EventName = eventName,IsAlarm = false}); } public void NotifyAlarm(string alarmName, Dictionary dvid) { _lstEvent.Enqueue(new FaEventItem() { dvid = dvid, EventName = alarmName, IsAlarm = true }); } public void SetLocalControl() { Task.Factory.StartNew(() => { _gem.SetLocal(); }); } public void SetRemoteControl() { Task.Factory.StartNew(() => { _gem.SetRemote(); }); } public void SetEnableSpooling() { Task.Factory.StartNew(() => { _gem .SetAttribute(GEMVariables.SpoolEnabled, AttributeType.EC, "true"); }); } public void SetDisableSpooling() { Task.Factory.StartNew(() => { _gem .SetAttribute(GEMVariables.SpoolEnabled, AttributeType.EC, "false"); }); } public bool MonitorFaTask() { try { FaEventItem ev; while (_lstEvent.TryDequeue(out ev)) { if (ev.dvid != null) { foreach (var dvid in ev.dvid) { SetDVIDValue(dvid.Key, dvid.Value); } } if (ev.IsAlarm) { SetAlarm(ev.EventName); } else { SendEvent(ev.EventName); } } SynchronizeSVIDValue(); } catch (Exception ex) { System.Diagnostics.Trace.WriteLine(ex); } return true; } private void OnCommunicationStateChanged(object sender, SECsEventArgs e) { if (_gem.CommunicationState == CommunicationState.EnabledCommunicating) { _gem.SetOnline(); _gem.SetRemote(); } } private void SynchronizeSVIDValue() { try { foreach (SVID sv in _gem.EquipmentModel.StatusVariables.SVIDCollection) { if (sv != null && !_systemBuildInVariables.Contains(sv.logicalName)) { if (sv.valueType == SECSFormats.List) { List svData = _equipment.GetListSvidValue(sv.logicalName); if (svData != null && svData.Count > 0) { SECsDataItem data = new SECsDataItem(SECsFormat.List); foreach (var item in svData) { data.Add(item, item); } _gem.SetListAttribute(sv.logicalName, AttributeType.SV, data); } else { SECsDataItem data = new SECsDataItem(SECsFormat.List); data.Clear(); _gem.SetListAttribute(sv.logicalName, AttributeType.SV, data); } } else { string svDataValue = _equipment.GetSvidValue(sv.logicalName); if (!string.IsNullOrEmpty(svDataValue)) { if (sv.valueType == SECSFormats.Boolean) svDataValue = ConvertToBoolean(svDataValue).ToString(); _gem.SetAttribute(sv.logicalName, AttributeType.SV, svDataValue); } } } } } catch (Exception ex) { LOG.Write("Synchronize FA Model Data exception:" + ex.Message); } } private bool SetDVIDValue(string localName, string value) { if (value == null) return false; //if (!string.IsNullOrEmpty(value)) //{ if (_gem.EquipmentModel == null || !_gem.EquipmentModel.DataVariables.DVIDCollection.IsExistLogicalName(localName)) return false; foreach (VariableType dv in _gem.EquipmentModel.DataVariables.DVIDCollection) { if (dv.logicalName == localName) { if (dv.valueType == SECSFormats.Boolean) { value = ConvertToBoolean(value).ToString(); } break; } } _gem.SetAttribute(localName, AttributeType.DV, value); //} return true; } private bool ConvertToBoolean(string value) { if (value == "0" || value.ToLower() == "false") return false; else return true; } private void SendEvent(string eventName) { try { if (_gem.EquipmentModel != null) { var allEvents = _gem.GetAllEnabledEvents(); if (allEvents.Contains(eventName)) { _gem.SendCollectionEvent(eventName); } else { //LOG.Write(string.Format("sendEvent failed,not find:", eventName)); } //LOG.Write(string.Format("【FA2SendEvent--{0}】", eventName)); } } catch (Exception ex) { LOG.Write("SendEvent Error:" + ex.Message); } } public void SetAlarm(string alarmTag) { Task.Factory.StartNew(() => { //if (_gem.IsAlarmSet(alarmTag)) //{ // _gem.ClearAlarm(alarmTag); //} var allAlarms = _gem.GetAllEnabledAlarms(); if (allAlarms.Contains(alarmTag)) { _gem.SetAlarm(alarmTag); } else { //WriteLog(string.Format("sendAlarm failed,not find:", alarmTag)); } //WriteLog(string.Format("【FA3SetAlarm--{0}】", alarmTag)); }); } } }