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() + { + + } + } +}