From 9ccbb49746b83194697ba9726279267e5ddfafcb Mon Sep 17 00:00:00 2001 From: hanqiangqiang <1364346467@qq.com> Date: Tue, 7 Jul 2026 14:58:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=B4=E6=97=B6=E4=BF=9D=E5=AD=98=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BB=BF=E7=9C=9F=E5=86=85=E5=AE=B9=20?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=97=A7=E7=9A=84=E4=BB=BF=E7=9C=9F=E8=B0=83?= =?UTF-8?q?=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/SicSimulator/Instances/SimulatorSystem.cs | 316 ++++++++++++++++-- .../AI_AORandom/SimulatorAI_AORandom.cs | 80 +++++ .../Device/SimulatorDeviceManager.cs | 188 +++++++++++ .../SimulatorCore/IoAO_AI/SimulatorIoAO_AI.cs | 70 ++++ .../SimulatorCore/IoDO_DI/SimulatorIoDO_DI.cs | 39 +++ .../IoDefault/SimulatorIoDefault.cs | 73 ++++ Framework/SimulatorCore/IoMFC/SimulatorMFC.cs | 92 +++++ .../IoPressure/SimulatorPressure.cs | 40 +++ .../IoValves/SimulatorIoValve.cs | 69 ++++ Framework/SimulatorCore/SimulatorCore.csproj | 10 +- 10 files changed, 952 insertions(+), 25 deletions(-) create mode 100644 Framework/SimulatorCore/AI_AORandom/SimulatorAI_AORandom.cs create mode 100644 Framework/SimulatorCore/Device/SimulatorDeviceManager.cs create mode 100644 Framework/SimulatorCore/IoAO_AI/SimulatorIoAO_AI.cs create mode 100644 Framework/SimulatorCore/IoDO_DI/SimulatorIoDO_DI.cs create mode 100644 Framework/SimulatorCore/IoDefault/SimulatorIoDefault.cs create mode 100644 Framework/SimulatorCore/IoMFC/SimulatorMFC.cs create mode 100644 Framework/SimulatorCore/IoPressure/SimulatorPressure.cs create mode 100644 Framework/SimulatorCore/IoValves/SimulatorIoValve.cs diff --git a/App/SicSimulator/Instances/SimulatorSystem.cs b/App/SicSimulator/Instances/SimulatorSystem.cs index 16098ee..9cd30e7 100644 --- a/App/SicSimulator/Instances/SimulatorSystem.cs +++ b/App/SicSimulator/Instances/SimulatorSystem.cs @@ -1,13 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.Eventing.Reader; +using Aitex.Common.Util; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.Log; using Aitex.Core.Util; using Aitex.Core.WCF; +using MECF.Framework.Common.Equipment; using MECF.Framework.Common.PLC; +using MECF.Framework.Simulator.Core; using SicSimulator.Views; +using System; +using System.Collections.Generic; +using System.Diagnostics.Eventing.Reader; +using System.Threading.Tasks; namespace SicSimulator.Instances { @@ -32,6 +36,10 @@ namespace SicSimulator.Instances WcfServiceManager.Instance.Initialize(new Type[] { typeof(SimulatorAdsPlcService) }); + //Singleton.Instance.Initialize(PathManager.GetCfgDir() + "DevicePM.xml", "GaN", ModuleName.PM1, "PM1"); + //Singleton.Instance.Initialize(PathManager.GetCfgDir() + "DevicePM.xml", "GaN", ModuleName.PM2, "PM2"); + //Singleton.Instance.Initialize(PathManager.GetCfgDir() + "DeviceTM.xml", "GaN", ModuleName.TM, "TM"); + _thread = new PeriodicJob(200, OnMonitor, nameof(SimulatorSystem), true); } @@ -350,34 +358,34 @@ namespace SicSimulator.Instances try { MonitorPressureTM(); - MonitorPressureLoad(); - MonitorPressureUnLoad(); - MonitorSlitValveFlow(); - MonitorTMValve(); + //MonitorPressureLoad(); + //MonitorPressureUnLoad(); + //MonitorSlitValveFlow(); + //MonitorTMValve(); MonitorPm("PM1"); MonitorPm("PM2"); MonitorValve("PM1"); MonitorValve("PM2"); - MonitorFlowRamp("PM1"); + //MonitorFlowRamp("PM1"); //MonitorFlowRamp("PM2"); - MonitorGasConnector("PM1"); - MonitorLid("PM1"); - MonitorLidSwing("PM1"); - MonitorConfinementRing("PM1"); - MonitorGasConnector("PM2"); - MonitorLid("PM2"); - MonitorLidSwing("PM2"); - MonitorConfinementRing("PM2"); - MonitorChamberMoveBody("PM1"); - MonitorChamberMoveBodyUp("PM1"); - MonitorHeater("PM1"); - MonitorRotation("PM1"); - MonitorChamberMoveBody("PM2"); - MonitorChamberMoveBodyUp("PM2"); - MonitorHeater("PM2"); - MonitorRotation("PM2"); + //MonitorGasConnector("PM1"); + //MonitorLid("PM1"); + //MonitorLidSwing("PM1"); + //MonitorConfinementRing("PM1"); + //MonitorGasConnector("PM2"); + //MonitorLid("PM2"); + //MonitorLidSwing("PM2"); + //MonitorConfinementRing("PM2"); + //MonitorChamberMoveBody("PM1"); + //MonitorChamberMoveBodyUp("PM1"); + //MonitorHeater("PM1"); + //MonitorRotation("PM1"); + //MonitorChamberMoveBody("PM2"); + //MonitorChamberMoveBodyUp("PM2"); + //MonitorHeater("PM2"); + //MonitorRotation("PM2"); } catch (Exception e) { @@ -915,6 +923,266 @@ namespace SicSimulator.Instances } + private void PmMotion(string pm) + { + IO.DI[$"{pm}.DI_PMSlitValveCloseCompleted"].Value = IO.DI[$"TM.DI_PM{(pm == "PM1" ? "A" : "B")}SlitValveClose"].Value; + + IO.DI[$"{pm}.DI_LockingCylinderLock"].Value = !IO.DO[$"{pm}.DO_LockingCylinderLockUnlock"].Value; + + if (IO.DO[$"{pm}.DO_ChamLidMotorAUp"].Value) + { + IO.DI[$"{pm}.DI_PMChamberLidDownpositioning"].Value = true; + Task.Delay(2000).ContinueWith(x => + { + IO.DI[$"{pm}.DI_PMChamberLidUppositioning"].Value = false; + }); + } + + if (IO.DO[$"{pm}.DO_ChamLidMotorADown"].Value) + { + IO.DI[$"{pm}.DI_PMChamberLidUppositioning"].Value = true; + Task.Delay(2000).ContinueWith(x => + { + IO.DI[$"{pm}.DI_PMChamberLidDownpositioning"].Value = false; + }); + } + DelaySetDoToDi(pm, "DI_PMChamberLidTighten", "DO_ChamLidTighten"); + DelaySetDoToDi(pm, "DI_PMChamberLidLoosen", "DO_ChamLidLoosen"); + DelaySetDoToDi(pm, "DI_PMChamberLidSwingLock", "DO_ChamLidSwingLock"); + DelaySetDoToDi(pm, "DI_PMChamberLidSwingUnLock", "DO_ChamLidSwingUnLock"); + DelaySetDoToDi(pm, "DI_PMChamberLidLock", "DO_ChamLidLockPL"); + DelaySetDoToDi(pm, "DI_PMChamberLidUnLock", "DO_ChamLidUnLockPL"); + + //磁流体仿真 + int temp = pm == "PM1" ? 0 : 1; + + if (!_pre_DO_SpindleHome[temp] && IO.DO[$"{pm}.DO_SpindleHome"].Value) + { + IO.DI[$"{pm}.DI_SpindleHomeFinish"].Value = false; + Task.Delay(1000).ContinueWith(x => + { + IO.AI[$"{pm}.AI_SpindleCurrentPosition"].Value = 0; + IO.DI[$"{pm}.DI_SpindleHomeFinish"].Value = true; + }); + } + _pre_DO_SpindleHome[temp] = IO.DO[$"{pm}.DO_SpindleHome"].Value; + + if (!_pre_DO_SpindleLoadAngleRun[temp] && IO.DO[$"{pm}.DO_SpindleLoadAngleRun"].Value) + { + IO.DI[$"{pm}.DI_SpindlePositionComplete"].Value = false; + Task.Delay(2000).ContinueWith(x => + { + IO.AI[$"{pm}.AI_SpindleCurrentPosition"].Value += IO.AO[$"{pm}.AO_SpindleLoadAngle"].Value; + if (IO.AI[$"{pm}.AI_SpindleCurrentPosition"].Value >= 360) + { + IO.AI[$"{pm}.AI_SpindleCurrentPosition"].Value -= 360; + } + IO.DI[$"{pm}.DI_SpindlePositionComplete"].Value = true; + }); + } + _pre_DO_SpindleLoadAngleRun[temp] = IO.DO[$"{pm}.DO_SpindleLoadAngleRun"].Value; + + if (!_pre_DO_SpindleMoveSlot[temp] && IO.DO[$"{pm}.DO_SpindleMoveSlot"].Value) + { + IO.AI[$"{pm}.AI_SpindleActualSlot"].Value = 0; + Task.Delay(2000).ContinueWith(x => + { + var s = (int)IO.AO[$"{pm}.AO_SpindleSlot"].Value; + if (s > 0 && s < 9) + { + IO.AI[$"{pm}.AI_SpindleCurrentPosition"].Value = IO.AO[$"{pm}.AO_SpindlePosition{s}"].Value; + IO.AI[$"{pm}.AI_SpindleActualSlot"].Value = s; + } + }); + } + _pre_DO_SpindleMoveSlot[temp] = IO.DO[$"{pm}.DO_SpindleMoveSlot"].Value; + + //shutter仿真 + if (IO.DO[$"{pm}.DO_ShutterUp"].Value) + { + Task.Delay(2000).ContinueWith(x => + { + IO.DI[$"{pm}.DI_ShutterUp"].Value = true; + IO.DI[$"{pm}.DI_ShutterDown"].Value = false; + }); + } + if (IO.DO[$"{pm}.DO_ShutterDown"].Value) + { + Task.Delay(2000).ContinueWith(x => + { + IO.DI[$"{pm}.DI_ShutterUp"].Value = false; + IO.DI[$"{pm}.DI_ShutterDown"].Value = true; + }); + } + if (IO.DO[$"{pm}.DO_ShutterForward"].Value) + { + Task.Delay(2000).ContinueWith(x => + { + IO.DI[$"{pm}.DI_ShutterForward"].Value = true; + IO.DI[$"{pm}.DI_ShutterBackward"].Value = false; + }); + } + if (IO.DO[$"{pm}.DO_ShutterBackward"].Value) + { + Task.Delay(2000).ContinueWith(x => + { + IO.DI[$"{pm}.DI_ShutterForward"].Value = false; + IO.DI[$"{pm}.DI_ShutterBackward"].Value = true; + }); + } + + ////V99仿真 + //if (IO.DO[$"{pm}.DO_PMPressureRelief"].Value && !IO.DO[$"{pm}.DO_PMPressureReliefClose"].Value) + //{ + // IO.DI[$"{pm}.DI_PMPressureReliefOpenFB"].Value = true; + // IO.DI[$"{pm}.DI_PMPressureReliefCloseFB"].Value = false; + //} + + //if (IO.DO[$"{pm}.DO_PMPressureReliefClose"].Value && !IO.DO[$"{pm}.DO_PMPressureRelief"].Value) + //{ + // IO.DI[$"{pm}.DI_PMPressureReliefOpenFB"].Value = false; + // IO.DI[$"{pm}.DI_PMPressureReliefCloseFB"].Value = true; + //} + } + + private void DelaySetDoToDi(string pm, string diName, string doName) + { + if (!IO.DO[$"{pm}.{doName}"].Value) + { + IO.DI[$"{pm}.{diName}"].Value = false; + return; + } + if (IO.DI[$"{pm}.{diName}"].Value != IO.DO[$"{pm}.{doName}"].Value) + { + Task.Delay(2000).ContinueWith(x => + { + IO.DI[$"{pm}.{diName}"].Value = IO.DO[$"{pm}.{doName}"].Value; + }); + } + } + + private void MonitorTVPm(string pm) + { + IO.AI[$"{pm}.AI_ButterflyValveActualMode"].Value = IO.AO[$"{pm}.AO_ButterflyValveSetMode"].Value; + //IO.AI[$"{pm}.AI_HeartBeat"].Value = IO.AO[$"{pm}.AO_HeartBeat"].Value; + + IO.AI[$"{pm}.AI_ButterflyValveActualPosition"].Value = IO.AO[$"{pm}.AO_ButterflyValveSetPosition"].Value; + + var mode = IO.AO[$"{pm}.AO_ButterflyValveSetMode"].Value; + //蝶阀开启,跟着蝶阀的设置值走 + if (IO.DO[$"{pm}.DO_ButterflyEnable"].Value) + { + if (mode == 5) + { + if (IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value > IO.AO[$"{pm}.AO_ButterflyValveSetPressure"].Value) + { + if (IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value - 30 > IO.AO[$"{pm}.AO_ButterflyValveSetPressure"].Value) + { + IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value -= 30; + } + else + { + IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value = IO.AO[$"{pm}.AO_ButterflyValveSetPressure"].Value; + } + } + else if (IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value < IO.AO[$"{pm}.AO_ButterflyValveSetPressure"].Value) + { + if (IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value + 10 < IO.AO[$"{pm}.AO_ButterflyValveSetPressure"].Value) + { + IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value += 10; + } + else + { + IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value = IO.AO[$"{pm}.AO_ButterflyValveSetPressure"].Value; + } + } + IO.AI[$"{pm}.AI_PMChamberPressure"].Value = IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value; + } + if (mode == 2) + { + if (IO.AO[$"{pm}.AO_ButterflyValveSetPosition"].Value > 0) + { + if (IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value > 0) + { + IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value -= (IO.AO[$"{pm}.AO_ButterflyValveSetPosition"].Value) / 8; + } + else + IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value = 0; + } + IO.AI[$"{pm}.AI_PMChamberPressure"].Value = IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value; + } + } + else + { + bool fontMfc = false; + for (int i = 70; i <= 89; i++) + { + if (IO.AI[$"{pm}.AI_M{i}"].Value > 100) + { + fontMfc = true; + continue; + } + } + + if (fontMfc) + { + if (IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value < 1200) + { + IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value += 10; + } + IO.AI[$"{pm}.AI_PMChamberPressure"].Value = IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value; + } + } + + //蝶阀Ramp有Bug,设置AO值可以化解 + //if (IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value >= 1100) + //{ + // IO.AO[$"{pm}.AO_ButterflyValveSetPressure"].Value = IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value; + //} + + //string s = pm == "PM1" ? "A" : "B"; + //if (IO.DI[$"TM.DI_TMPM{s}BanlanceFB"].Value || IO.DI[$"TM.DI_PM{s}GateValveOpen"].Value) + //{ + // var v1 = IO.AI[$"{pm}.AI_PMChamberPressure"].Value; + // var v2 = IO.AI[$"TM.AI_TMChamberPressure"].Value; + // if (v1 > v2) + // { + // IO.AI[$"TM.AI_TMChamberPressure"].Value = v1; + // } + // else + // { + // IO.AI[$"{pm}.AI_PMChamberPressure"].Value = v2; + // } + //} + //else + // IO.AI[$"{pm}.AI_PMChamberPressure"].Value = IO.AI[$"{pm}.AI_ButterflyValveActualPressure"].Value; + + //V27自动打开 + //if (IO.AI[$"{pm}.AI_ChamPress"].Value > 1020 && IO.DO[$"{pm}.DO_PumpBypass(V27)"].Value != true) + //{ + // IO.DO[$"{pm}.DO_PumpBypass(V27)"].Value = true; + //} + //if (IO.AI[$"{pm}.AI_ChamPress"].Value < 900 && IO.DO[$"{pm}.DO_PumpBypass(V27)"].Value) + //{ + // IO.DO[$"{pm}.DO_PumpBypass(V27)"].Value = false; + //} + + if (IO.DO[$"{pm}.DO_SpindleSpeedRun"].Value) + { + IO.AI[$"{pm}.AI_SpindleCurrentSpeed"].Value = IO.AO[$"{pm}.AO_SpindleVelocity"].Value; + } + else + IO.AI[$"{pm}.AI_SpindleCurrentSpeed"].Value = 0; + + //设置PT2的压力比PT1的小20 + var pt2 = IO.AI[$"{pm}.AI_PMChamberPressure"].Value - 20; + if (pt2 > 0) + { + IO.AI[$"{pm}.AI_ColdtrapExitPressure"].Value = pt2; + } + IO.AI[$"{pm}.AI_ColdtrapExitPressure"].Value = IO.AI[$"{pm}.AI_PMChamberPressure"].Value - 20 > 0 ? IO.AI[$"{pm}.AI_PMChamberPressure"].Value - 20 : 0; + } + private void MonitorValve(string pm) { diff --git a/Framework/SimulatorCore/AI_AORandom/SimulatorAI_AORandom.cs b/Framework/SimulatorCore/AI_AORandom/SimulatorAI_AORandom.cs new file mode 100644 index 0000000..735fa7a --- /dev/null +++ b/Framework/SimulatorCore/AI_AORandom/SimulatorAI_AORandom.cs @@ -0,0 +1,80 @@ +using Aitex.Core.RT.Device; +using Aitex.Core.RT.IOCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace MECF.Framework.Simulator.Core +{ + public class SimulatorAI_AORandom : BaseDevice, IDevice + { + protected List AI_AOList = new List(); + private readonly Random _rnd = new Random(); + + public SimulatorAI_AORandom(string module, XmlElement node, string ioModule = "") : base(module, node, ioModule) + { + InitializeIValve(node); + } + + /// + /// 根据XML配置创建MFC控制对象 + /// + /// + protected virtual void InitializeIValve(XmlElement node) + { + XmlNodeList valveNodes = node.GetElementsByTagName("Random"); + foreach (XmlElement xmlElement in valveNodes) + { + AI_AORandomData randomData = new AI_AORandomData() + { + Type = xmlElement.GetAttribute("type"), + Name = xmlElement.GetAttribute("ioName"), + BaseValue = Convert.ToSingle(xmlElement.GetAttribute("baseValue")) + }; + AI_AOList.Add(randomData); + } + } + + protected override void HandleMonitor() + { + Random(); + } + + protected virtual void Random() + { + foreach (var ai_ao in AI_AOList) + { + if (ai_ao.Type == "AI") + IO.AI[$"{Module}.{ai_ao.Name}"].Value = ai_ao.BaseValue + (float)_rnd.NextDouble(); + else if (ai_ao.Type == "AO") + IO.AO[$"{Module}.{ai_ao.Name}"].Value = ai_ao.BaseValue + (float)_rnd.NextDouble(); + } + } + + public bool Initialize() + { + return true; + } + + public void Reset() + { + + } + + public void Terminate() + { + + } + } + + public class AI_AORandomData + { + public string Type { get; set; } + public string Name { get; set; } + public float BaseValue { get; set; } + } +} diff --git a/Framework/SimulatorCore/Device/SimulatorDeviceManager.cs b/Framework/SimulatorCore/Device/SimulatorDeviceManager.cs new file mode 100644 index 0000000..43eb25f --- /dev/null +++ b/Framework/SimulatorCore/Device/SimulatorDeviceManager.cs @@ -0,0 +1,188 @@ +using Aitex.Core.RT.DataCenter; +using Aitex.Core.RT.Device; +using Aitex.Core.RT.Log; +using Aitex.Core.Util; +using MECF.Framework.Common.Equipment; +using MECF.Framework.Common.Utilities; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Xml; + +namespace MECF.Framework.Simulator.Core +{ + public class SimulatorDeviceManager + { + private readonly Dictionary _nameDevice = new Dictionary(); + private readonly object _lockerDevice = new object(); + private readonly R_TRIG _trigExceed500 = new R_TRIG(); + private readonly Dictionary> _typeDevice = new Dictionary>(); + private readonly ConcurrentBag _optionDevice = new ConcurrentBag(); + private PeriodicJob _thread; + + /// + /// 设置或返回是否以异步方式初始化当前管理器中的设备。 + /// + public bool DisableAsyncInitialize { get; set; } + /// + /// 返回当前设备管理器映射的XML配置文件节点。 + /// + protected XmlElement DeviceModelNodes { get; private set; } + + + /// + /// 向设备管理器的设备字典中添加一个设备实例。 + /// + /// + protected virtual void QueueDevice(IDevice device) + { + QueueDevice($"{device.Module}.{device.Name}", device); + } + + /// + /// 向设备管理器的设备字典中添加一个设备实例,并自定义该设备在字典中的Key。 + /// + /// + /// + protected void QueueDevice(string key, IDevice device) + { + lock (_lockerDevice) + { + Debug.Assert(!_nameDevice.ContainsKey(key), "DeviceModel config file contains duplicated name " + key); + _nameDevice.Add(key, device); + } + } + + public void Initialize(string modelFile, string type, ModuleName mod, string ioModule = "") + { + if (!File.Exists(modelFile)) + { + throw new ApplicationException($"did not find the device model file {modelFile} "); + } + var xmlDocument = new XmlDocument(); + try + { + xmlDocument.Load(modelFile); + if (!(xmlDocument.SelectSingleNode("DeviceModelDefine") is XmlElement xmlElement)) + { + throw new ApplicationException($"device mode file {modelFile} is not valid"); + } + var attribute = xmlElement.GetAttribute("type"); + if (attribute != type) + { + throw new ApplicationException($"the type {attribute} in device mode file {modelFile} is inaccordance with the system type {type}"); + } + DeviceModelNodes = xmlElement; + foreach (XmlNode childNode in xmlElement.ChildNodes) + { + if (childNode.NodeType == XmlNodeType.Comment || !(childNode is XmlElement xmlElement2)) + { + continue; + } + var text = xmlElement2.GetAttribute("assembly"); + if (string.IsNullOrEmpty(text)) + { + text = "MECF.Framework.RT.EquipmentLibrary"; + } + var text2 = xmlElement2.Name.Substring(0, xmlElement2.Name.Length - 1); + var text3 = xmlElement2.GetAttribute("classType"); + if (string.IsNullOrEmpty(text3)) + { + text3 = "Aitex.Core.RT.Device.Unit." + text2; + } + var assembly = Assembly.Load(text); + var type2 = assembly.GetType(text3); + if (type2 == null) + { + continue; + } + foreach (var childNode2 in xmlElement2.ChildNodes) + { + if (!(childNode2 is XmlElement xmlElement3)) + { + LOG.Write("Device Model File contains non element node, " + (childNode2 as XmlNode).Value); + continue; + } + var device = Activator.CreateInstance(type2, mod.ToString(), xmlElement3, ioModule) as IDevice; + if (xmlElement3.HasAttribute("option") && Convert.ToBoolean(xmlElement3.Attributes["option"].Value)) + { + _optionDevice.Add(device); + continue; + } + QueueDevice(device); + DATA.Subscribe(device, $"{device.Module}.{text2}.{device.Name}"); + if (!_typeDevice.ContainsKey(type2)) + { + _typeDevice[type2] = new List(); + } + _typeDevice[type2].Add(device); + if (DisableAsyncInitialize) + { + InitDevice(device); + continue; + } + var task = Task.Run(delegate + { + InitDevice(device); + }); + } + } + + _thread = new PeriodicJob(200, Monitor, "SimulatorSystem", true); + } + catch (Exception ex) + { + LOG.Write(ex); + } + } + + private void InitDevice(IDevice device) + { + try + { + if (!device.Initialize()) + { + LOG.Write(device.Name + " initialize failed."); + } + } + catch (Exception ex) + { + LOG.Write(ex); + } + } + + /// + /// 后台扫面线程调用的方法。 + /// + public bool Monitor() + { + lock (_lockerDevice) + { + foreach (var value in _nameDevice.Values) + { + try + { + PerformanceMonitor.MonitorRun(() => + { + value.Monitor(); + return true; + }, 500, _trigExceed500, out _, $"{value.Module}.{value.Name} monitor"); + } + catch (Exception ex) + { + LOG.Write(ex, $"{ModuleName.Diagnosis} Monitor {value.Name} Exception"); + } + } + } + + return true; + } + } +} diff --git a/Framework/SimulatorCore/IoAO_AI/SimulatorIoAO_AI.cs b/Framework/SimulatorCore/IoAO_AI/SimulatorIoAO_AI.cs new file mode 100644 index 0000000..ecec000 --- /dev/null +++ b/Framework/SimulatorCore/IoAO_AI/SimulatorIoAO_AI.cs @@ -0,0 +1,70 @@ +using Aitex.Core.RT.Device; +using Aitex.Core.RT.IOCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace MECF.Framework.Simulator.Core +{ + public class SimulatorIoAO_AI : BaseDevice, IDevice + { + protected Dictionary AO_AI = new Dictionary(); + + public SimulatorIoAO_AI(string module, XmlElement node, string ioModule) : base(module, node, ioModule) + { + InitializeIValve(node); + } + + /// + /// 根据XML配置创建气阀控制对象 + /// + /// + protected virtual void InitializeIValve(XmlElement node) + { + XmlNodeList valveNodes = node.GetElementsByTagName("AO_AI"); + foreach (XmlElement xmlElement in valveNodes) + { + string aiName = xmlElement.GetAttribute("ai"); + string aoName = xmlElement.GetAttribute("ao"); + if (!AO_AI.ContainsKey(aiName) && !AO_AI.ContainsKey(aoName)) + AO_AI.Add(aiName, aoName); + + var isDefaultOpen = xmlElement.GetAttribute("aoDefault"); + if (!String.IsNullOrWhiteSpace(isDefaultOpen)) + IO.AO[$"{Module}.{aoName}"].Value = Convert.ToSingle(isDefaultOpen); + } + } + + protected override void HandleMonitor() + { + DoValueToDI(); + } + + protected void DoValueToDI() + { + foreach (var ai_ao in AO_AI) + { + IO.AI[$"{Module}.{ai_ao.Key}"].Value = IO.AO[$"{Module}.{ai_ao.Value}"].Value; + } + } + + public bool Initialize() + { + return true; + } + + public void Reset() + { + + } + + public void Terminate() + { + + } + } +} diff --git a/Framework/SimulatorCore/IoDO_DI/SimulatorIoDO_DI.cs b/Framework/SimulatorCore/IoDO_DI/SimulatorIoDO_DI.cs new file mode 100644 index 0000000..24dc353 --- /dev/null +++ b/Framework/SimulatorCore/IoDO_DI/SimulatorIoDO_DI.cs @@ -0,0 +1,39 @@ +using Aitex.Core.RT.IOCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace MECF.Framework.Simulator.Core +{ + public class SimulatorIoDO_DI : SimulatorIoValve + { + public SimulatorIoDO_DI(string module, XmlElement node, string ioModule) : base(module, node, ioModule) + { + + } + + /// + /// 根据XML配置创建气阀控制对象 + /// + /// + protected override void InitializeIValve(XmlElement node) + { + XmlNodeList valveNodes = node.GetElementsByTagName("DO_DI"); + foreach (XmlElement xmlElement in valveNodes) + { + string diName = xmlElement.GetAttribute("di"); + string doName = xmlElement.GetAttribute("do"); + if (!DI_DOList.ContainsKey(diName) && !DI_DOList.ContainsKey(doName)) + DI_DOList.Add(diName, doName); + + var isDefaultOpen = xmlElement.GetAttribute("doDefault"); + if (!String.IsNullOrWhiteSpace(isDefaultOpen)) + IO.DO[$"{Module}.{doName}"].Value = Convert.ToBoolean(isDefaultOpen); + } + } + + } +} diff --git a/Framework/SimulatorCore/IoDefault/SimulatorIoDefault.cs b/Framework/SimulatorCore/IoDefault/SimulatorIoDefault.cs new file mode 100644 index 0000000..6e6cc38 --- /dev/null +++ b/Framework/SimulatorCore/IoDefault/SimulatorIoDefault.cs @@ -0,0 +1,73 @@ +using Aitex.Core.RT.Device; +using Aitex.Core.RT.IOCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; + +namespace MECF.Framework.Simulator.Core +{ + public class SimulatorIoDefault : BaseDevice, IDevice + { + protected Dictionary IO_ValueList = new Dictionary(); + private readonly Random _rnd = new Random(); + + public SimulatorIoDefault(string module, XmlElement node, string ioModule = "") : base(module, node, ioModule) + { + InitializeIValve(node); + } + + /// + /// 根据XML配置创建IO对象初始默认值 + /// + /// + protected virtual void InitializeIValve(XmlElement node) + { + XmlNodeList valveNodes = node.GetElementsByTagName("IODefault"); + foreach (XmlElement xmlElement in valveNodes) + { + string type = xmlElement.GetAttribute("type"); + string ioName = xmlElement.GetAttribute("ioName"); + string value = xmlElement.GetAttribute("default"); + switch (type) + { + case "DI": + IO.DI[$"{Module}.{ioName}"].Value = Convert.ToBoolean(value); + break; + + case "DO": + IO.DO[$"{Module}.{ioName}"].Value = Convert.ToBoolean(value); + break; + + case "AI": + IO.AI[$"{Module}.{ioName}"].Value = Convert.ToSingle(value); + break; + + case "AO": + IO.AO[$"{Module}.{ioName}"].Value = Convert.ToSingle(value); + break; + } + } + } + + public bool Initialize() + { + return true; + } + + public void Reset() + { + + } + + public void Terminate() + { + + } + } +} diff --git a/Framework/SimulatorCore/IoMFC/SimulatorMFC.cs b/Framework/SimulatorCore/IoMFC/SimulatorMFC.cs new file mode 100644 index 0000000..633a430 --- /dev/null +++ b/Framework/SimulatorCore/IoMFC/SimulatorMFC.cs @@ -0,0 +1,92 @@ +using Aitex.Core.RT.Device; +using Aitex.Core.RT.IOCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace MECF.Framework.Simulator.Core +{ + public class SimulatorMFC : BaseDevice, IDevice + { + protected Dictionary AI_AOList = new Dictionary(); + private readonly Random _rnd = new Random(); + + public SimulatorMFC(string module, XmlElement node, string ioModule = "") : base(module, node, ioModule) + { + InitializeIValve(node); + } + + /// + /// 根据XML配置创建MFC控制对象 + /// + /// + protected virtual void InitializeIValve(XmlElement node) + { + XmlNodeList valveNodes = node.GetElementsByTagName("IoMfc"); + foreach (XmlElement xmlElement in valveNodes) + { + string aiFlow = xmlElement.GetAttribute("aiFlow"); + string aoFlow = xmlElement.GetAttribute("aoFlow"); + if (!AI_AOList.ContainsKey(aiFlow) && !AI_AOList.ContainsKey(aoFlow)) + AI_AOList.Add(aiFlow, aoFlow); + + } + } + + protected override void HandleMonitor() + { + Ramp(); + } + + protected virtual void Ramp() + { + foreach (var ai_ao in AI_AOList) + { + float setpoint = 0; + float result = 0; + float current = 0; + if (IO.AI[$"{Module}.{ai_ao.Key}"] != null) + { + current = IO.AI[$"{Module}.{ai_ao.Key}"].Value; + setpoint = IO.AO[$"{Module}.{ai_ao.Value}"].Value; + } + + + if (current >= setpoint) + { + result = current - 50; + if (result < setpoint) + result = setpoint; + } + if (current < setpoint) + { + result = current + 50; + if (result > setpoint) + result = setpoint; + } + + result = result + (float)_rnd.NextDouble(); + + IO.AI[$"{Module}.{ai_ao.Key}"].Value = result; + } + } + + public bool Initialize() + { + return true; + } + + public void Reset() + { + + } + + public void Terminate() + { + + } + } +} diff --git a/Framework/SimulatorCore/IoPressure/SimulatorPressure.cs b/Framework/SimulatorCore/IoPressure/SimulatorPressure.cs new file mode 100644 index 0000000..7e0db33 --- /dev/null +++ b/Framework/SimulatorCore/IoPressure/SimulatorPressure.cs @@ -0,0 +1,40 @@ +using Aitex.Core.RT.Device; +using Aitex.Core.RT.IOCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace MECF.Framework.Simulator.Core +{ + public class SimulatorPressure : SimulatorMFC + { + public SimulatorPressure(string module, XmlElement node, string ioModule) : base(module, node, ioModule) + { + + } + + /// + /// 根据XML配置创建PC控制对象 + /// + /// + protected override void InitializeIValve(XmlElement node) + { + XmlNodeList valveNodes = node.GetElementsByTagName("IoPressureMeter"); + foreach (XmlElement xmlElement in valveNodes) + { + string aiValue = xmlElement.GetAttribute("aiValue"); + string aoValue = xmlElement.GetAttribute("aoValue"); + + if (!String.IsNullOrWhiteSpace(aoValue)) + if (!AI_AOList.ContainsKey(aiValue) && !AI_AOList.ContainsKey(aoValue)) + AI_AOList.Add(aiValue, aoValue); + + } + } + } +} diff --git a/Framework/SimulatorCore/IoValves/SimulatorIoValve.cs b/Framework/SimulatorCore/IoValves/SimulatorIoValve.cs new file mode 100644 index 0000000..d276aa8 --- /dev/null +++ b/Framework/SimulatorCore/IoValves/SimulatorIoValve.cs @@ -0,0 +1,69 @@ +using Aitex.Core.RT.Device; +using Aitex.Core.RT.IOCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace MECF.Framework.Simulator.Core +{ + public class SimulatorIoValve : BaseDevice, IDevice + { + protected Dictionary DI_DOList = new Dictionary(); + + public SimulatorIoValve(string module, XmlElement node, string ioModule) : base(module, node, ioModule) + { + InitializeIValve(node); + } + + /// + /// 根据XML配置创建气阀控制对象 + /// + /// + protected virtual void InitializeIValve(XmlElement node) + { + XmlNodeList valveNodes = node.GetElementsByTagName("IoValve"); + foreach (XmlElement xmlElement in valveNodes) + { + string diName = xmlElement.GetAttribute("diOpen"); + string doName = xmlElement.GetAttribute("doOpen"); + if (!DI_DOList.ContainsKey(diName) && !DI_DOList.ContainsKey(doName)) + DI_DOList.Add(diName, doName); + + var isDefaultOpen = xmlElement.GetAttribute("isDefaultOpen"); + if (!String.IsNullOrWhiteSpace(isDefaultOpen)) + IO.DO[$"{Module}.{doName}"].Value = Convert.ToBoolean(isDefaultOpen); + } + } + + protected override void HandleMonitor() + { + DoValueToDI(); + } + + protected void DoValueToDI() + { + foreach (var di_do in DI_DOList) + { + IO.DI[$"{Module}.{di_do.Key}"].Value = IO.DO[$"{Module}.{di_do.Value}"].Value; + } + } + + public bool Initialize() + { + return true; + } + + public void Reset() + { + + } + + public void Terminate() + { + + } + } +} diff --git a/Framework/SimulatorCore/SimulatorCore.csproj b/Framework/SimulatorCore/SimulatorCore.csproj index 22797cb..80bfdbf 100644 --- a/Framework/SimulatorCore/SimulatorCore.csproj +++ b/Framework/SimulatorCore/SimulatorCore.csproj @@ -62,6 +62,7 @@ + HPA48View.xaml @@ -75,6 +76,13 @@ HoneywellBarcodeView.xaml + + + + + + + SGLoadPortView.xaml @@ -575,7 +583,7 @@ - + \ No newline at end of file