diff --git a/.gitignore b/.gitignore
index 0690263..fa06879 100644
--- a/.gitignore
+++ b/.gitignore
@@ -367,3 +367,4 @@ FodyWeavers.xsd
/MECF.Framework.Common/MECF.Framework.Common.und
*.DotSettings
Output/
+BuildTools/
diff --git a/Dependencies/KXGEM.dll b/Dependencies/KXGEM.dll
new file mode 100644
index 0000000..5e019f4
Binary files /dev/null and b/Dependencies/KXGEM.dll differ
diff --git a/MECF.Framework.Common/MECF.Framework.Common.csproj b/MECF.Framework.Common/MECF.Framework.Common.csproj
index a1b62be..7441e64 100644
--- a/MECF.Framework.Common/MECF.Framework.Common.csproj
+++ b/MECF.Framework.Common/MECF.Framework.Common.csproj
@@ -59,6 +59,10 @@
False
..\Dependencies\FabConnect.dll
+
+ False
+ ..\Dependencies\KXGEM.dll
+
False
..\Dependencies\log4net.dll
@@ -748,6 +752,7 @@
+
diff --git a/MECF.Framework.Common/MECF/Framework/Common/Gem/GemManager.cs b/MECF.Framework.Common/MECF/Framework/Common/Gem/GemManager.cs
new file mode 100644
index 0000000..62e5a5a
--- /dev/null
+++ b/MECF.Framework.Common/MECF/Framework/Common/Gem/GemManager.cs
@@ -0,0 +1,822 @@
+using Aitex.Common.Util;
+using Aitex.Core.RT.DataCenter;
+using Aitex.Core.RT.OperationCenter;
+using Aitex.Core.Util;
+using Kxware.Automation.Secs;
+using Kxware.Common;
+using Kxware.Connectivity.Remoting;
+using Kxware.ToolAutomation.Capabilities;
+using Kxware.ToolAutomation;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.IO;
+using Aitex.Core.RT.Event;
+using Aitex.Core.RT.SCCore;
+using Aitex.Core.RT.Log;
+using SciChart.Core.Extensions;
+
+namespace MECF.Framework.Common.Gem
+{
+ public class GemManager : Singleton
+ {
+ public string PPIDNoExtension { get; set; }
+
+ public string LotID { get; set; }
+
+ private string JobID = "";
+
+ private string RtStatus => DATA.Poll("Rt.Status").ToString();
+
+ private Kxware.ToolAutomation.Equipment _equipment;
+ public Kxware.ToolAutomation.Equipment Equipment => _equipment;
+
+ private PeriodicJob _monitorJob;
+
+ public string CommunicationState => _equipment.GetCommunicationState().ToString();
+
+ public string ControlMode => _equipment.GetControlState().ToString();
+
+ public string SequenceRecipeContent { get; set; }
+
+ public string RecvMsgFromHost { get; set; }
+
+ public string ProgramLog { get; set; }
+
+ public string SecsLog { get; set; }
+
+ public List AlarmInfoList { get; set; } = new List();
+
+ public List EventInfoList { get; set; } = new List();
+
+ public List SequenceRecipeNameList => _equipment?.GetRecipeList(_equipment.MasterConnectionName);
+
+ public List VariableList
+ {
+ get
+ {
+ var result = _equipment?.GetVariables()?.Select(p => new Kxware.Connectivity.Remoting.VariableData()
+ {
+ ConnectionName = p.ConnectionName,
+ SmlValue = p.GetSecsValue().ToSML(SmlFormat.RoundBracket),
+ Default = p.Default?.ToString(),
+ Description = p.Description,
+ HostVisible = p.HostVisible,
+ Id = p.Id,
+ IsCommonVariable = p.IsCommonVariable,
+ LimitEventName = p.LimitEvent?.Name,
+ Name = p.Name,
+ Max = p.Max?.ToString(),
+ Min = p.Min?.ToString(),
+ Persistent = p.Persistent,
+ Unit = p.Unit,
+ VariableType = (enumVariableTypes)p.VariableType
+ }).ToList();
+
+ return result;
+ }
+ }
+
+ public List EventList
+ {
+ get
+ {
+ var result = _equipment?.GetEvents()?.Select(p => new Kxware.Connectivity.Remoting.EventData()
+ {
+ EventName = p.Name,
+ EventId = p.Id,
+ Description = p.Description
+ }).ToList();
+
+ return result;
+ }
+ }
+
+ public List AlarmList
+ {
+ get
+ {
+ var result = _equipment?.GetAlarms()?.Select(p => new Kxware.Connectivity.Remoting.AlarmData()
+ {
+ Name = p.Name,
+ AlarmID = p.ALID,
+ ALCD = p.ALCD,
+ AlarmText = p.ALTX,
+ Description = p.Description
+ }).ToList();
+
+ return result;
+ }
+ }
+
+ public void Initialize()
+ {
+ try
+ {
+ //注册
+ DATA.Subscribe("GEM.CommunicationState", () => CommunicationState);
+ DATA.Subscribe("GEM.ControlMode", () => ControlMode);
+ DATA.Subscribe("GEM.VariableList", () => VariableList);
+ DATA.Subscribe("GEM.EventList", () => EventList);
+ DATA.Subscribe("GEM.EventInfoList", () => EventInfoList);
+ DATA.Subscribe("GEM.AlarmList", () => AlarmList);
+ DATA.Subscribe("GEM.AlarmInfoList", () => AlarmInfoList);
+ DATA.Subscribe("GEM.SequenceRecipeNameList", () => SequenceRecipeNameList);
+ DATA.Subscribe("GEM.SequenceRecipeContent", () => SequenceRecipeContent);
+ DATA.Subscribe("GEM.RecvMsgFromHost", () => RecvMsgFromHost);
+ DATA.Subscribe("GEM.ProgramLog", () => ProgramLog);
+ DATA.Subscribe("GEM.SecsLog", () => SecsLog);
+ DATA.Subscribe("GEM.PPID", () => PPIDNoExtension);
+ DATA.Subscribe("GEM.LotID", () => LotID);
+
+ OP.Subscribe($"GEM_SetSoftwareVersion", (string cmd, object[] args) => SetSoftwareVersion((string)args[0]));
+ OP.Subscribe($"GEM_SetEnable", (string cmd, object[] args) => SetEnable((bool)args[0]));
+ OP.Subscribe($"GEM_SetControlMode", (string cmd, object[] args) => SetControlMode(args[0].ToString()));
+ OP.Subscribe($"GEM_SelectSequenceRecipeChanged", (string cmd, object[] args) => SelectSequenceRecipeChanged(args[0].ToString()));
+ OP.Subscribe($"GEM_TerminalMessageConfirm", (string cmd, object[] args) => TerminalMessageConfirm());
+ OP.Subscribe($"GEM_SendMessageToHost", (string cmd, object[] args) => SendMessageToHost(args[0].ToString()));
+ OP.Subscribe($"GEM_ClearProgramLog", (string cmd, object[] args) => ClearProgramLog());
+ OP.Subscribe($"GEM_ClearSecsLog", (string cmd, object[] args) => ClearSecsLog());
+ OP.Subscribe($"GEM_ClearAllAlarm", (string cmd, object[] args) => ClearAllAlarm());
+ OP.Subscribe($"GEM_ClearModuleAlarm", (string cmd, object[] args) => ClearModuleAlarm(args[0].ToString()));
+ OP.Subscribe($"GEM_PPChange", (string cmd, object[] args) => PPChange(args));
+
+ string equipmentName = SC.GetStringValue("System.EquipmentName");
+ int equipmentNo = SC.GetValue("System.EquipmentNo");
+ _equipment = new Kxware.ToolAutomation.Equipment(equipmentName);
+
+ //_equipment.RegisteringVariables += new RegisterVariableDelegate(RegisteringVariables);
+
+ //_equipment.RegisteringAlarms += new RegisterAlarmDelegate(RegisteringAlarms);
+
+ //initialize SECS/ GEM service from configruation file
+ _equipment.Initialize(PathManager.GetCfgDir() + "Gem.exml");
+
+ #region 设置变量
+
+ //设置内置名称,软件版本等SV
+ _equipment.SetValue("MDLN", "Sic");
+ _equipment.SetValue("Manufacturer", "Sicentury");
+ _equipment.SetValue("EqpSerialNum", equipmentNo.ToString());
+
+ //设置Recipes路径
+ _equipment.SetValue("PPDirectory", "./Recipes");
+ _equipment.SetValue("PPFileExtension", "seq,rcp");
+
+ //设置PPFormat
+ _equipment.SetValue("PPFormat", 1);
+
+ //设置Log路径
+ //Log.SetLoggingDirectory("");
+
+ #endregion
+
+ #region 回调
+
+ _equipment.AlarmSET += new OnAlarmSET(AlarmSET);
+ _equipment.AlarmCLEAR += new OnAlarmCLEAR(AlarmCLEAR);
+
+ Kxware.Common.Log.NewMessage += Log_NewMessage;
+
+ _equipment.DataMessageReceived += DataMessageReceived;
+ _equipment.DataMessageSent += DataMessageSent;
+
+ _equipment.TerminalMessageReceived += TerminalMessageReceived;
+
+ //注册远程操作指令
+ _equipment.RegisterRemoteCommandHandler("GO-LOCAL", OnReceivedRemoteCommand);
+ _equipment.RegisterRemoteCommandHandler("GO-REMOTE", OnReceivedRemoteCommand);
+ _equipment.RegisterRemoteCommandHandler("PP-SELECT", OnReceivedRemoteCommand);
+ _equipment.RegisterRemoteCommandHandler("CREATE-JOB", OnReceivedRemoteCommand);
+ _equipment.RegisterRemoteCommandHandler("START", OnReceivedRemoteCommand);
+ _equipment.RegisterRemoteCommandHandler("ABORT", OnReceivedRemoteCommand);
+ _equipment.RegisterRemoteCommandHandler("STOP", OnReceivedRemoteCommand);
+
+ _equipment.EventTriggered += EventTriggered;
+
+ //register custom SECS message
+ _equipment.RegisterMessageHandler(7, 7, HandleS7F7);
+
+ //Variable value change callback
+ var allHostECs = _equipment.GetVariables().FindAll(p => p.HostVisible && p.VariableType == VariableType.EC);
+ allHostECs.ForEach(v =>
+ {
+ v.AdvancedValueChanged += Variable_AdvancedValueChanged;
+ });
+
+ #endregion
+
+ //enable GEM
+ _equipment.GemEnable();
+ _equipment.OnlineLocal(_equipment.MasterConnectionName);
+
+ _monitorJob = new PeriodicJob(1000, Monitor, "GEM_Monitor", true);
+ }
+ catch (Exception ex)
+ {
+ //LOG.Error(ex.Message,ex);
+ }
+ }
+
+ private void Variable_AdvancedValueChanged(Variable variable, SecsValue oldValue, SecsValue newValue, enumSource source)
+ {
+ //由Host主机修改的EC
+ if (source == enumSource.Host)
+ {
+
+ }
+ }
+
+ private void HandleS7F7(DataMessage message)
+ {
+ //实现对S7F7的解析处理
+ var node = (SecsAscii)message.Body;
+ var MID = node.GetValueAsString();
+ Kxware.Common.Log.Info("GEM", $"Received S7F7:\r\n{message.ToSML(SmlFormat.Standard)}");
+
+ //回复消息分类
+ {
+ //无异常
+ var s7f8 = new ReplyMessage(message);
+ var l = new SecsList();
+ l.AddChild(new SecsU4(0));
+ l.AddChild(new SecsBoolean(true));
+ s7f8.Body = l;
+ _equipment?.SendMessage(_equipment.MasterConnectionName, s7f8);
+ }
+
+ //{
+ // //Unrecognized device ID(无法识别的设备ID)
+ // var s9f1 = new ReplyMessage(message);
+ // _equipment.SendMessage(_equipment.MasterConnectionName, s9f1);
+ //}
+
+ //{
+ // //Unrecognized stream type(无法识别的流类型)
+ // var s9f3 = new ReplyMessage(message);
+ // _equipment.SendMessage(_equipment.MasterConnectionName, s9f3);
+ //}
+
+ //{
+ // //Unrecognized function type(无法识别的函数类型)
+ // var s9f5 = new ReplyMessage(message);
+ // _equipment.SendMessage(_equipment.MasterConnectionName, s9f5);
+ //}
+
+ //{
+ // //Illegal data(非法数据)
+ // var s9f7 = new ReplyMessage(message);
+ // _equipment.SendMessage(_equipment.MasterConnectionName, s9f7);
+ //}
+
+ //{
+ // //Transaction timer timeout(事务定时器超时)
+ // var s9f5 = new ReplyMessage(message);
+ // _equipment.SendMessage(_equipment.MasterConnectionName, s9f5);
+ //}
+
+ //{
+ // //Conversation timeout(会话超时)
+ // var s9f5 = new ReplyMessage(message);
+ // _equipment.SendMessage(_equipment.MasterConnectionName, s9f5);
+ //}
+ }
+
+ private void HandleS7F65(DataMessage message)
+ {
+ //实现对S7F65的解析处理
+ var listNode = (SecsList)message.Body;
+ var ppID = listNode[0].GetValueAsString();
+ var pmID = listNode[1].GetValueAsString();
+ //TODO: perform the command
+ var s7f66 = new ReplyMessage(message);
+ s7f66.Body = new SecsBinary(0);
+ _equipment.SendMessage(_equipment.MasterConnectionName, s7f66);
+ }
+
+ private void SendCustomMessage()
+ {
+ var s99f1 = new DataMessage(99, 1, true);
+ var list1 = new SecsList();
+ list1.AddChild(new SecsAscii("SMIFReady"));
+ list1.AddChild(new SecsList());
+ s99f1.Body = list1;
+
+ _equipment.SendMessage(_equipment.MasterConnectionName, s99f1);
+ }
+
+ private bool Monitor()
+ {
+ try
+ {
+ //设置变量值
+ //SetValue();
+
+ SetXmlValue();
+
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Kxware.Common.Log.Error(ex.Source, ex.Message, ex);
+ LOG.Error(ex.Message, ex);
+ return false;
+ }
+ }
+
+ //设置GEM配置文件中变量的值
+ private void SetXmlValue()
+ {
+ SortedDictionary> keyValues = Singleton.Instance.GetDBRecorderList();
+
+ foreach (Variable variable in _equipment.GetVariables())
+ {
+ if (variable.VariableType == VariableType.SV)
+ {
+ if (keyValues.ContainsKey(variable.Name))
+ {
+ _equipment?.SetValue(variable.Name, keyValues[variable.Name]());
+ }
+ else
+ {
+ //排除Gem 内置变量
+ if (variable.Id > 10000)
+ {
+ //LOG.Warning($"DATA no Contain Gem Varibable name {variable.Name}");
+ }
+ }
+ }
+ }
+ }
+
+ private void SetValue()
+ {
+ SortedDictionary> keyValues = Singleton.Instance.GetDBRecorderList();
+
+ foreach (KeyValuePair> item in keyValues)
+ {
+ //判断类型,排除引用类型
+ object obj = item.Value();
+ if (obj != null)
+ {
+ Type type = obj.GetType();
+ if (type == typeof(bool) || type == typeof(double) || type == typeof(float) || type == typeof(int) || type == typeof(ushort) ||
+ type == typeof(short) || type == typeof(long) || type == typeof(string))
+ {
+ _equipment?.SetValue(item.Key, obj);
+ }
+ }
+ }
+ }
+
+ private IEnumerable RegisteringVariables()
+ {
+ List variableDefinitionList = new List();
+
+ int index = 0;
+
+ SortedDictionary> keyValues = Singleton.Instance.GetDBRecorderList();
+
+ foreach (KeyValuePair> item in keyValues)
+ {
+ //判断类型,排除引用类型
+ object obj = item.Value();
+ if (obj != null)
+ {
+ Type type = obj.GetType();
+ if (type == typeof(bool) || type == typeof(double) || type == typeof(float) || type == typeof(int) || type == typeof(ushort) ||
+ type == typeof(short) || type == typeof(long) || type == typeof(string))
+ {
+ ValueFormat valueFormat = ValueFormat.F8;
+
+ if (type == typeof(bool))
+ {
+ valueFormat = ValueFormat.BOOLEAN;
+ }
+ else if (type == typeof(int))
+ {
+ valueFormat = ValueFormat.I8;
+ }
+ else if (type == typeof(long))
+ {
+ valueFormat = ValueFormat.I8;
+ }
+ else if (type == typeof(short))
+ {
+ valueFormat = ValueFormat.I8;
+ }
+ else if (type == typeof(ushort))
+ {
+ valueFormat = ValueFormat.U8;
+ }
+ else if (type == typeof(float))
+ {
+ valueFormat = ValueFormat.F4;
+ }
+ else if (type == typeof(double))
+ {
+ valueFormat = ValueFormat.F4;
+ }
+ else if (type == typeof(string))
+ {
+ valueFormat = ValueFormat.A;
+ }
+
+ variableDefinitionList.Add(new VariableDefinition(Kxware.Common.VariableType.SV, valueFormat, (ulong)(1100000 + index), item.Key, (string)null, (string)null, (string)null, (string)null, (string)null, false, true, ""));
+
+ index++;
+ }
+ }
+ }
+
+ return variableDefinitionList;
+ }
+
+ private IEnumerable RegisteringAlarms()
+ {
+ List alarmDefinitionList = new List();
+
+ int index = 0;
+
+ SortedDictionary> keyValues = Singleton.Instance.GetDBRecorderList();
+
+ foreach (KeyValuePair> item in keyValues)
+ {
+ //alarmDefinitionList.Add(new AlarmDefinition((ulong)(1000000 + index),));
+
+ index++;
+ }
+
+ return alarmDefinitionList;
+ }
+
+ private void AlarmSET(string equipmentName, string connectionName, ulong alarmID, string alarmName, string altx, Kxware.Common.AlarmCode alcd, string alarmDescription, string alarmAdditionalInformation, string setEvent, string clearEvent, DateTime occurredTime, Kxware.Common.VariableData[] associatedVariables, DataMessage alarmSecsMessage)
+ {
+ if (connectionName == _equipment.MasterConnectionName)
+ {
+ AlarmInfoList.Add($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} 【触发】 ID:{alarmID} {altx}");
+ while (AlarmInfoList.Count > 100)
+ {
+ AlarmInfoList.RemoveAt(0);
+ }
+ }
+ }
+
+ private void AlarmCLEAR(string equipmentName, string connectionName, ulong alarmID, string alarmName, string altx, Kxware.Common.AlarmCode alcd, string alarmDescription, string alarmAdditionalInformation, string setEvent, string clearEvent, DateTime occurredTime, Kxware.Common.VariableData[] associatedVariables, DataMessage alarmSecsMessage)
+ {
+ if (connectionName == _equipment.MasterConnectionName)
+ {
+ AlarmInfoList.Add($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} 【清除】 ID:{alarmID} {altx}");
+ while (AlarmInfoList.Count > 100)
+ {
+ AlarmInfoList.RemoveAt(0);
+ }
+ }
+ }
+
+ private void DataMessageSent(string equipmentName, string connectionName, DateTime time, Kxware.Automation.Secs.DataMessage message)
+ {
+ if (connectionName == _equipment.MasterConnectionName)
+ {
+ string msg = $"{time.ToString("yyyy/MM/dd HH:mm:ss.fff")} 【发送】\r\n{message.ToSML()}\r\n";
+ Kxware.Common.Log.Info("GEM", msg);
+ SecsLog += msg;
+
+ //if (SecsLog.Length > 10000)
+ //{
+ // SecsLog = SecsLog.Substring(SecsLog.Length - 10000);
+ //}
+ }
+ }
+
+ private void Log_NewMessage(LogType loggingType, string customizedLogTypeName, DateTime timeStamp, string processName, int threadID, string source, string message)
+ {
+ // make a filter, do not show SML logging message at current window
+ if (message.Contains("SECS MSG Recv") || message.Contains("SECS MSG Sent"))
+ {
+ return;
+ }
+
+ ProgramLog += $"{timeStamp.ToString("yyyy/MM/dd HH:mm:ss,fff")} {source} 线程ID:{threadID} 内容:{message}\r\n";
+ }
+
+ private void DataMessageReceived(string equipmentName, string connectionName, DateTime time, Kxware.Automation.Secs.DataMessage message)
+ {
+ if (connectionName == _equipment.MasterConnectionName)
+ {
+ string msg = $"{time.ToString("yyyy/MM/dd HH:mm:ss.fff")} 【接受】\r\n{message.ToSML()}\r\n";
+ Kxware.Common.Log.Info("GEM", msg);
+ SecsLog += msg;
+
+ //if (SecsLog.Length > 10000)
+ //{
+ // SecsLog = SecsLog.Substring(SecsLog.Length - 10000);
+ //}
+ }
+ }
+
+ private void EventTriggered(string equipmentName, string connectionName, ulong eventID, string eventName, string eventDescription, Kxware.Common.VariableData[] associatedVariables, Kxware.Automation.Secs.DataMessage eventSecsMessage)
+ {
+ if (connectionName == _equipment.MasterConnectionName)
+ {
+ var associatedDataInfo = "";
+ if (associatedVariables.Length > 0)
+ {
+ associatedDataInfo = "关联数据:" + string.Join(",", associatedVariables.Select(p => p.Name + " " + p.Value.ToSML(Kxware.Common.SmlFormat.RoundBracket)));
+ }
+ EventInfoList.Add($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} 编号:{eventID} 事件名:{eventName} {associatedDataInfo}");
+ }
+ }
+
+ private enumRemoteCommandAckCode OnReceivedRemoteCommand(string connectionName, string objSpec, string remoteCommand, List remoteCommandParameters)
+ {
+ //只接受从MasterConnection 收到的控制命令
+ if (connectionName != _equipment.MasterConnectionName)
+ return enumRemoteCommandAckCode.CannotPerformNow;
+
+ //判断控制状态,在Local 状态下只接受GO-REMOTE命令
+ var currentCtrlState = _equipment.GetControlState();
+ if (currentCtrlState != GEMControlStates.Online_Remote)
+ {
+ if (remoteCommand.ToUpper() != "GO-REMOTE")
+ return enumRemoteCommandAckCode.CannotPerformNow;
+ }
+
+ var result = enumRemoteCommandAckCode.NoSuchObjectExists;
+ switch (remoteCommand.ToUpper())
+ {
+ case "GO-LOCAL":
+ {
+ if (currentCtrlState == GEMControlStates.Online_Remote)
+ {
+ _equipment.OnlineLocal(_equipment.MasterConnectionName);
+ result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
+ }
+ else
+ result = enumRemoteCommandAckCode.RejectedAlreadyInDesiredCondition;
+ }
+ break;
+
+ case "GO-REMOTE":
+ {
+ if (currentCtrlState == GEMControlStates.Online_Remote)
+ {
+ result = enumRemoteCommandAckCode.RejectedAlreadyInDesiredCondition;
+ }
+ else if (!_equipment.OnlineRemote(_equipment.MasterConnectionName, out string error))
+ result = enumRemoteCommandAckCode.CannotPerformNow;
+ else
+ result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
+ }
+ break;
+
+ //PP-SELECT指令附加参数(PPID&LotID)
+ case "PP-SELECT":
+ {
+ try
+ {
+ if (RtStatus != "AutoIdle")
+ {
+ Kxware.Common.Log.Warn("GEM", $"Cannot perform 'PP-SELECT' command. Equipment State is not in AutoIdle.");
+ result = enumRemoteCommandAckCode.CannotPerformNow;
+ }
+ else if (remoteCommandParameters.Find(p => p.CPNAME == "PPID") == null)
+ {
+ Kxware.Common.Log.Warn("GEM", $"Cannot perform 'PP-SELECT' command. PPID is not specified.");
+ result = enumRemoteCommandAckCode.AtLeastOneParameterIsInvalid;
+ }
+ else if (remoteCommandParameters.Find(p => p.CPNAME == "LotID") == null)
+ {
+ Kxware.Common.Log.Warn("GEM", $"Cannot perform 'PP-SELECT' command. LotID is not specified.");
+ result = enumRemoteCommandAckCode.AtLeastOneParameterIsInvalid;
+ }
+ else
+ {
+ string PPID = remoteCommandParameters.Find(p => p.CPNAME == "PPID").CPVAL.GetValueAsString();
+ PPIDNoExtension = PPID.Replace(@"Sequence\", "").Replace(".seq", "");
+ LotID = remoteCommandParameters.Find(p => p.CPNAME == "LotID").CPVAL.GetValueAsString();
+ Kxware.Common.Log.Info("GEM", $"Received 'PP-SELECT' command. PPID={PPID}, LotID={LotID}");
+
+ //Check if rcpID is exist. if not exist, returen enumRemoteCommandAckCode.AtLeastOneParameterIsInvalid
+
+ result = enumRemoteCommandAckCode.AcknowledgeCommandWillBePerformed;
+ }
+ }
+ catch (Exception)
+ {
+ result = enumRemoteCommandAckCode.AtLeastOneParameterIsInvalid;
+ }
+ }
+ break;
+
+ //CREATE-JOB指令没有附加参数
+ case "CREATE-JOB":
+ {
+ if (RtStatus != "AutoIdle")
+ {
+ Kxware.Common.Log.Warn("GEM", $"Cannot perform 'CREATE-JOB' command. Equipment State is not in AutoIdle.");
+ result = enumRemoteCommandAckCode.CannotPerformNow;
+ }
+ else
+ {
+ Kxware.Common.Log.Info("GEM", $"Received 'CREATE-JOB' command.");
+ result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
+
+ //具体操作
+ JobID = "CJ_Local_Load_" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
+ Dictionary dictionary = new Dictionary
+ {
+ { "JobId", JobID},
+ { "Module", "LoadLock" },
+ {"SlotSequence",new string[]{PPIDNoExtension} },
+ { "LotId", LotID },
+ { "AutoStart", true }
+ };
+
+ OP.DoOperation("System.CreateJob", dictionary);
+ }
+ }
+ break;
+
+ //START指令没有附加参数
+ case "START":
+ {
+ if (RtStatus != "AutoIdle" && RtStatus != "AutoRunning")
+ {
+ Kxware.Common.Log.Warn("GEM", $"Cannot perform 'STRAT' command. Equipment State is not in AutoIdle or AutoRunning.");
+ result = enumRemoteCommandAckCode.CannotPerformNow;
+ }
+ else
+ {
+ Kxware.Common.Log.Info("GEM", $"Received 'STRAT' command.");
+ result = enumRemoteCommandAckCode.AcknowledgeCommandWillBePerformed;
+
+ //具体操作
+ OP.DoOperation("System.StartJob", JobID);
+ }
+ }
+ break;
+
+ //ABORT指令没有附加参数
+ case "ABORT":
+ case "STOP":
+ {
+ if (RtStatus != "AutoRunning")
+ {
+ Kxware.Common.Log.Warn("GEM", $"Cannot perform 'ABORT' command. Equipment State is not in AutoRunning.");
+ result = enumRemoteCommandAckCode.CannotPerformNow;
+ }
+ else
+ {
+ Kxware.Common.Log.Info("GEM", $"Received 'ABORT' command.");
+ result = enumRemoteCommandAckCode.AcknowledgeCommandWillBePerformed;
+
+ //具体操作
+ OP.DoOperation("System.Abort");
+ }
+ }
+ break;
+
+ default:
+ {
+ Kxware.Common.Log.Error("GEM", $"Un-handled remote command: {remoteCommand}");
+ }
+
+ break;
+ }
+
+ return result;
+ }
+
+ private bool SetSoftwareVersion(string softwareVersion)
+ {
+ _equipment.SetValue("SOFTREV", softwareVersion);
+
+ return true;
+ }
+
+ private bool SetEnable(bool enable)
+ {
+ if (enable)
+ {
+ _equipment.GemEnable();
+ }
+ else
+ {
+ _equipment.GemDisable();
+ }
+
+ return true;
+ }
+
+ private bool SetControlMode(string mode)
+ {
+ switch (mode)
+ {
+ case "OnlineRemote":
+ {
+ _equipment?.OnlineRemote(_equipment.MasterConnectionName);
+ }
+ break;
+
+ case "OnlineLocal":
+ {
+ _equipment?.OnlineLocal(_equipment.MasterConnectionName);
+ }
+ break;
+
+ case "Offline":
+ {
+ _equipment?.Offline(_equipment.MasterConnectionName);
+ }
+ break;
+ }
+
+ return true;
+ }
+
+ private bool SelectSequenceRecipeChanged(string sequenceRecipeName)
+ {
+ if (!string.IsNullOrEmpty(sequenceRecipeName))
+ {
+ SequenceRecipeContent = File.ReadAllText(".\\Recipes\\" + sequenceRecipeName);
+ }
+
+ return true;
+ }
+
+ private bool ClearProgramLog()
+ {
+ ProgramLog = "";
+
+ return true;
+ }
+
+ private bool ClearSecsLog()
+ {
+ SecsLog = "";
+
+ return true;
+ }
+
+ private bool ClearAllAlarm()
+ {
+ foreach (var alarm in _equipment?.GetAlarms().Where(a => a.Active))
+ {
+ _equipment?.ClearAlarm(alarm.Name, alarm.AdditionalInfo);
+ }
+
+ return true;
+ }
+
+ private bool ClearModuleAlarm(string module)
+ {
+ foreach (var alarm in _equipment?.GetAlarms().Where(a => a.Name == $"{module}Alarm" && a.Active))
+ {
+ _equipment?.ClearAlarm(alarm.Name, alarm.AdditionalInfo);
+ }
+
+ return true;
+ }
+
+ private bool PPChange(object[] args)
+ {
+ if (args != null && args.Length == 2)
+ {
+ //PPChangeStatus: 1:created; 2:edited; 3:deleted
+ _equipment?.TriggerEvent("PPChange", new string[] { "PPChangeName", "PPChangeStatus", "EventTime" }, new object[] { args[0], args[1],
+ DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")});
+ }
+
+ return true;
+ }
+
+ //接受终端消息
+ private void TerminalMessageReceived(string equipmentName, string connectionName, int terminalID, List texts)
+ {
+ RecvMsgFromHost += $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} [{terminalID}] {string.Join("\r\n", texts)}\r\n";
+ Kxware.Common.Log.Info("GEM", $"Received TERMIAL message :{connectionName} :{terminalID}, {string.Join(",", texts)}");
+ }
+
+ //终端消息确认
+ private bool TerminalMessageConfirm()
+ {
+ _equipment?.TriggerEvent("MessageRecognition", new string[] { "Clock" }, new object[] { DateTime.Now.ToString() });
+
+ return true;
+ }
+
+ //发送消息给主机
+ private bool SendMessageToHost(string sendMsg)
+ {
+ _equipment?.TerminalRequest(_equipment.MasterConnectionName, 0, sendMsg);
+
+ return true;
+ }
+
+ public void Terminate()
+ {
+
+ }
+ }
+}