using Aitex.Common.Util; using Aitex.Core.RT.Device; using Aitex.Core.RT.Log; using Aitex.Core.UI.Control; using Aitex.Core.Util; using MECF.Framework.Common.Device.Festo; using MECF.Framework.Common.Device.Wago; using MECF.Framework.Common.Net; using MECF.Framework.Common.Simulator; using MECF.Framework.Simulator.Core.Driver; using System; using System.Collections.Generic; using System.IO; using static MECF.Framework.Common.Simulator.MotorSimulator; namespace CyberX8_Simulator.Devices { public class WagoSocketSimulator : SocketDeviceSimulator { private const short WRITE_DO_STARTADDRESS = 0x0200; private const short WRITE_AO_STARTADDRESS = 0x0200; //键是名字,值是对应数据所在的位置 注意:要和WagoControlCfg里面的地址顺序对上 public Dictionary DONameIndexDic; public Dictionary DINameIndexDic; public Dictionary AINameIndexDic; public Dictionary AONameIndexDic; private IByteTransform byteTransform = new BigEndianByteTransformBase(); //存储模拟器数据的数组 public byte[] DOBytes = new byte[200]; public short[] AOShorts = new short[200]; public byte[] DIBytes = new byte[200]; public short[] AIShorts = new short[200]; /// /// 写DO锁 /// private object _writeDOLocker = new object(); /// /// 写AO锁 /// private object _writeAOLocker = new object(); /// /// Festo Data Buffer /// private Dictionary _festoDataBuffer = new Dictionary(); /// /// Name-WagoDO dictionary /// private Dictionary _doNameWagoDODic = new Dictionary(); /// /// Name-WagoDI dictionary /// private Dictionary _diNameWagoDIDic = new Dictionary(); /// /// 定时器 /// private PeriodicJob _LoaderPeriodicJob; private PeriodicJob _Wago2PeriodicJob; private PeriodicJob _Wago4PeriodicJob; private bool _rinse1FillValve = false; private bool _rinse1DumpValve = false; private bool _rinse2FillValve = false; private bool _rinse2DumpValve = false; private bool _rinse3FillValve = false; private bool _rinse3DumpValve = false; private bool _rinse4FillValve = false; private bool _rinse4DumpValve = false; private bool _reservoir1PumpOn = false; private int _srd1currentVacuumValue; private int _srd2currentVacuumValue; private int _port; //delegate #region Delegate public delegate void VariableValueChanged(object obj); public delegate void UpdateVariableValueWagoDatasChanged(string sourceName, string targetName, bool value,bool invert); #endregion #region 事件 /// /// 变量变更事件 /// public event VariableValueChanged OnDIVariableValueChanged; public event VariableValueChanged OnAIVariableValueChanged; public event VariableValueChanged OnDOVariableValueChanged; public event VariableValueChanged OnAOVariableValueChanged; #endregion public WagoSocketSimulator(int port):base(port) { SimulatorCommManager.Instance.OnUpdateVariableValueChanged += UpdataDataCausedByOtherModule; MotorSimulator.Instance.OnUpdateWagoDatasChanged += UpdataDataCausedByOtherModule; InitializeData(port); _port = port; } private void UpdataDataCausedByOtherModule(string sourceName,string name, bool value, bool invert) { value = invert ? !value : value; //AI Data if (AINameIndexDic.ContainsKey(name)) { switch (name) { case "r_LoaderA_LS_Vacuum_anlg": case "r_LoaderB_LS_Vacuum_anlg": AIShorts[AINameIndexDic[name]] = value ? (short)0x32C8 : (short)0x2AF8; break; case "r_DPUF_A_CHUCK_A_VAC": case "r_DPUF_A_CHUCK_B_VAC": AIShorts[AINameIndexDic[name]] = value ? (short)0x0C80 : (short)0x32C8; break; case "r_LOADERA_BERNOULLI_PRESSURE": case "r_LOADERB_BERNOULLI_PRESSURE": case "r_LOADERA_CHUCK_BLADDER": case "r_LOADERB_CHUCK_BLADDER": case "r_LOADERA_WS_BLADDER_PRESSURE": case "r_LOADERB_WS_BLADDER_PRESSURE": AIShorts[AINameIndexDic[name]] = value ? (short)0x2AF8 : (short)0x00; break; case "r_PREWET_DI_PRESS": AIShorts[AINameIndexDic[name]] = value ? (short)15000 : (short)3276; AIShorts[AINameIndexDic["r_PREWET_FLOW"]] = value ? (short)25000 : (short)3276; break; default: break; } } if (!string.IsNullOrEmpty(sourceName)) { switch (sourceName) { case "c_QDRD1_DI_FILL": _rinse1FillValve = value; break; case "c_QDRD1_DUMP": _rinse1DumpValve = value; break; case "c_QDRD2_DI_FILL": _rinse2FillValve = value; break; case "c_QDRD2_DUMP": _rinse2DumpValve = value; break; case "c_QDRD3_DI_FILL": _rinse3FillValve = value; break; case "c_QDRD3_DUMP": _rinse3DumpValve = value; break; case "c_QDRD4_DI_FILL": _rinse4FillValve = value; break; case "c_QDRD4_DUMP": _rinse4DumpValve = value; break; case "c_METAL1_PUMP_ON": _reservoir1PumpOn = value; break; default: break; } } //DI Data UpdataDIBytes(name, value ? 1 : 0); //Festo Data if (name == "FlowTestClamp") _festoDataBuffer[name] = value; } /// /// 触发Wago对应数据更新 /// /// /// private void UpdateDataCausedByWago(int position, bool value) { //Puf Simulator if (DONameIndexDic.ContainsKey("c_PUF_CHUCK") && position == DONameIndexDic["c_PUF_CHUCK"]) { value = _doNameWagoDODic["c_PUF_CHUCK"].Invert? !value : value; UpdataDIBytes("r_PUF_A_CHUCK_OUT", value ? 1 : 0); UpdataDIBytes("r_PUF_B_CHUCK_OUT", value ? 1 : 0); UpdataDIBytes("r_PUF_A_CHUCK_IN", !value ? 1 : 0); UpdataDIBytes("r_PUF_B_CHUCK_IN", !value ? 1 : 0); } //HVD Simulator if (DONameIndexDic.ContainsKey("c_HVD_1_HIGH") && position == DONameIndexDic["c_HVD_1_HIGH"]) { value = _doNameWagoDODic["c_HVD_1_HIGH"].Invert ? !value : value; UpdataAIShorts("r_HVD_1_ANALOG", value ? 4500 : 0); } if (DONameIndexDic.ContainsKey("c_HVD_2_HIGH") && position == DONameIndexDic["c_HVD_2_HIGH"]) { value = _doNameWagoDODic["c_HVD_2_HIGH"].Invert ? !value : value; UpdataAIShorts("r_HVD_2_ANALOG", value ? 4500 : 0); } //SRD Simulator //Lift UP if (DONameIndexDic.ContainsKey("c_SRD1_LIFT_UP") && position == DONameIndexDic["c_SRD1_LIFT_UP"]) { value = (_doNameWagoDODic["c_SRD1_LIFT_UP"].Invert ^ _diNameWagoDIDic["r_SRD1_LIFT_UP"].Invert) ? !value : value; UpdataDIBytes("r_SRD1_LIFT_UP", value ? 1 : 0); } if (DONameIndexDic.ContainsKey("c_SRD2_LIFT_UP") && position == DONameIndexDic["c_SRD2_LIFT_UP"]) { value = (_doNameWagoDODic["c_SRD2_LIFT_UP"].Invert ^ _diNameWagoDIDic["r_SRD2_LIFT_UP"].Invert) ? !value : value; UpdataDIBytes("r_SRD2_LIFT_UP", value ? 1 : 0); } //Flippers if (DONameIndexDic.ContainsKey("c_SRD1_150_FLIPPERS_IN") && position == DONameIndexDic["c_SRD1_150_FLIPPERS_IN"]) { value = (_doNameWagoDODic["c_SRD1_150_FLIPPERS_IN"].Invert ^ _diNameWagoDIDic["r_SRD1_150_FLIPPER1_OUT"].Invert) ? !value : value; UpdataDIBytes("r_SRD1_150_FLIPPER1_OUT", value ? 0 : 1); UpdataDIBytes("r_SRD1_150_FLIPPER2_OUT", value ? 0 : 1); UpdataDIBytes("r_SRD1_150_FLIPPER3_OUT", value ? 0 : 1); } if (DONameIndexDic.ContainsKey("c_SRD2_150_FLIPPERS_IN") && position == DONameIndexDic["c_SRD2_150_FLIPPERS_IN"]) { value = (_doNameWagoDODic["c_SRD2_150_FLIPPERS_IN"].Invert ^ _diNameWagoDIDic["r_SRD2_150_FLIPPER1_OUT"].Invert) ? !value : value; UpdataDIBytes("r_SRD2_150_FLIPPER1_OUT", value ? 0 : 1); UpdataDIBytes("r_SRD2_150_FLIPPER2_OUT", value ? 0 : 1); UpdataDIBytes("r_SRD2_150_FLIPPER3_OUT", value ? 0 : 1); } if (DONameIndexDic.ContainsKey("c_SRD1_200_FLIPPERS_IN") && position == DONameIndexDic["c_SRD1_200_FLIPPERS_IN"]) { value = (_doNameWagoDODic["c_SRD1_200_FLIPPERS_IN"].Invert ^ _diNameWagoDIDic["r_SRD1_200_FLIPPER1_OUT"].Invert) ? !value : value; UpdataDIBytes("r_SRD1_200_FLIPPER1_OUT", value ? 0 : 1); UpdataDIBytes("r_SRD1_200_FLIPPER2_OUT", value ? 0 : 1); UpdataDIBytes("r_SRD1_200_FLIPPER3_OUT", value ? 0 : 1); } if (DONameIndexDic.ContainsKey("c_SRD2_200_FLIPPERS_IN") && position == DONameIndexDic["c_SRD2_200_FLIPPERS_IN"]) { value = (_doNameWagoDODic["c_SRD2_200_FLIPPERS_IN"].Invert ^ _diNameWagoDIDic["r_SRD2_200_FLIPPER1_OUT"].Invert) ? !value : value; UpdataDIBytes("r_SRD2_200_FLIPPER1_OUT", value ? 0 : 1); UpdataDIBytes("r_SRD2_200_FLIPPER2_OUT", value ? 0 : 1); UpdataDIBytes("r_SRD2_200_FLIPPER3_OUT", value ? 0 : 1); } //Shuttle if (DONameIndexDic.ContainsKey("c_SRD1_Shutter_Close") && position == DONameIndexDic["c_SRD1_Shutter_Close"]) { value = (_doNameWagoDODic["c_SRD1_Shutter_Close"].Invert ^ _diNameWagoDIDic["r_SRD1_SHUTTER_OPEN"].Invert) ? !value : value; UpdataDIBytes("r_SRD1_SHUTTER_OPEN", value ? 0 : 1); UpdataDIBytes("r_SRD1_SHUTTER_CLOSED", value ? 1 : 0); } if (DONameIndexDic.ContainsKey("c_SRD2_Shutter_Close") && position == DONameIndexDic["c_SRD2_Shutter_Close"]) { value = (_doNameWagoDODic["c_SRD2_Shutter_Close"].Invert ^ _diNameWagoDIDic["r_SRD2_SHUTTER_OPEN"].Invert) ? !value : value; UpdataDIBytes("r_SRD2_SHUTTER_OPEN", value ? 0 : 1); UpdataDIBytes("r_SRD2_SHUTTER_CLOSED", value ? 1 : 0); } //Vacuum if (DONameIndexDic.ContainsKey("c_SRD1_CHUCK_VACUUM") && position == DONameIndexDic["c_SRD1_CHUCK_VACUUM"]) { value = (_doNameWagoDODic["c_SRD1_CHUCK_VACUUM"].Invert ) ? !value : value; _srd1currentVacuumValue = value ? 5000 : 15000; UpdataAIShorts("r_SRD1_CHUCK_VACUUM_anlg", _srd1currentVacuumValue); UpdataDIBytes("r_SRD1_CHUCK_VAC_OK", value ? 0 : 1); } if (DONameIndexDic.ContainsKey("c_SRD2_CHUCK_VACUUM") && position == DONameIndexDic["c_SRD2_CHUCK_VACUUM"]) { value = _doNameWagoDODic["c_SRD2_CHUCK_VACUUM"].Invert ? !value : value; _srd2currentVacuumValue = value ? 5000 : 15000; UpdataAIShorts("r_SRD2_CHUCK_VACUUM_anlg", _srd2currentVacuumValue); UpdataDIBytes("r_SRD2_CHUCK_VAC_OK", value ? 0 : 1); } if (DONameIndexDic.ContainsKey("c_SRD1_CHUCK_ATM_ON") && position == DONameIndexDic["c_SRD1_CHUCK_ATM_ON"]) { value = _doNameWagoDODic["c_SRD1_CHUCK_ATM_ON"].Invert ? !value : value; _srd1currentVacuumValue = value ? _srd1currentVacuumValue - 8000 : _srd1currentVacuumValue; UpdataAIShorts("r_SRD1_CHUCK_VACUUM_anlg", _srd1currentVacuumValue); } if (DONameIndexDic.ContainsKey("c_SRD2_CHUCK_ATM_ON") && position == DONameIndexDic["c_SRD2_CHUCK_ATM_ON"]) { value = _doNameWagoDODic["c_SRD2_CHUCK_ATM_ON"].Invert ? !value : value; _srd2currentVacuumValue = value ? _srd2currentVacuumValue - 8000 : _srd2currentVacuumValue; UpdataAIShorts("r_SRD2_CHUCK_VACUUM_anlg", _srd2currentVacuumValue); } //Water if (DONameIndexDic.ContainsKey("c_SRD1_WATER_ON") && position == DONameIndexDic["c_SRD1_WATER_ON"]) { value = _doNameWagoDODic["c_SRD1_WATER_ON"].Invert ? !value : value; UpdataAIShorts("r_SRD1_WATER_FLOW", value ? 30000 : 3277); } if (DONameIndexDic.ContainsKey("c_SRD2_WATER_ON") && position == DONameIndexDic["c_SRD2_WATER_ON"]) { value = _doNameWagoDODic["c_SRD2_WATER_ON"].Invert ? !value : value; UpdataAIShorts("r_SRD2_WATER_FLOW", value ? 30000 : 3277); } //metal 1 pump if (DONameIndexDic.ContainsKey("c_METAL1_PUMP_ON") && position == DONameIndexDic["c_METAL1_PUMP_ON"]) { value = _doNameWagoDODic["c_METAL1_PUMP_ON"].Invert ? !value : value; UpdataDIBytes("r_METAL1_PUMP_ON", value ? 1 : 0); } } /// /// 初始化字典 /// private void InitializeData(int port) //端口用于初始化不同Wago设备的字典 { //加载对应配置文件 WagoControllerCfg-Simulator.xml try { string oldXmlPath = PathManager.GetCfgDir(); string newXmlPath = oldXmlPath.Replace("CyberX8_Simulator", "CyberX8_RT") + "Devices\\WagoControllerCfg-Simulator.xml"; WagoControllerCfg cfg = CustomXmlSerializer.Deserialize(new FileInfo(newXmlPath)); if (cfg != null) { foreach (WagoDeviceConfig config in cfg.WagoDeviceConfigs) { if (port == config.Port) { if(config.Module == "Loader" && _LoaderPeriodicJob == null) { _LoaderPeriodicJob = new PeriodicJob(100, OnTimer, $"Wago {config.Module} timer",true); } if (config.Module == "Wago2" && _Wago2PeriodicJob == null) { _Wago2PeriodicJob = new PeriodicJob(100, OnTimer1, $"Wago {config.Module} timer", true); } if (config.Module == "Wago4" && _Wago2PeriodicJob == null) { _Wago2PeriodicJob = new PeriodicJob(100, OnTimer3, $"Wago {config.Module} timer", true); } //加载DO int i = 0; DONameIndexDic = new Dictionary(); if(config.WagoDigOut != null && config.WagoDigOut.WagoDOGroups != null) { foreach (var group in config.WagoDigOut.WagoDOGroups) { foreach (var item in group.WagoDOs) { DONameIndexDic[item.Name] = i; i++; _doNameWagoDODic[item.Name] = item; } } } //加载DI i = 0; DINameIndexDic = new Dictionary(); if(config.WagoDigIn != null && config.WagoDigIn.WagoDIGroups != null) { foreach (var group in config.WagoDigIn.WagoDIGroups) { foreach (var item in group.WagoDIs) { DINameIndexDic[item.Name] = i; i++; _diNameWagoDIDic[item.Name] = item; } } } //加载AO i = 0; AONameIndexDic = new Dictionary(); if (config.WagoAnoOut != null && config.WagoAnoOut.WagoAOGroups != null) { foreach (var group in config.WagoAnoOut.WagoAOGroups) { foreach (var item in group.WagoAOs) { AONameIndexDic[item.Name] = i; i++; } } } //加载AI i = 0; AINameIndexDic = new Dictionary(); if (config.WagoAnoIn != null && config.WagoAnoIn.WagoAIGroups != null) { foreach (var group in config.WagoAnoIn.WagoAIGroups) { foreach (var item in group.WagoAIs) { AINameIndexDic[item.Name] = i; i++; } } } } } } } catch { LOG.WriteLog(eEvent.ERR_WAGO, "Wago", "Load wago WagoControllerCfg-Simulator.xml failed"); } //设置IO变量默认值 if (AINameIndexDic.ContainsKey("r_LoaderA_LS_Vacuum_anlg")) AIShorts[AINameIndexDic["r_LoaderA_LS_Vacuum_anlg"]] = 0x32C8; if (AINameIndexDic.ContainsKey("r_LoaderB_LS_Vacuum_anlg")) AIShorts[AINameIndexDic["r_LoaderB_LS_Vacuum_anlg"]] = 0x32C8; if (AINameIndexDic.ContainsKey("r_DPUF_A_CHUCK_A_VAC")) AIShorts[AINameIndexDic["r_DPUF_A_CHUCK_A_VAC"]] = 0x32C8; if (AINameIndexDic.ContainsKey("r_DPUF_A_CHUCK_B_VAC")) AIShorts[AINameIndexDic["r_DPUF_A_CHUCK_B_VAC"]] = 0x32C8; if (AINameIndexDic.ContainsKey("r_SYSTEM_EXHAUST")) AIShorts[AINameIndexDic["r_SYSTEM_EXHAUST"]] = 0x3A98; if (DONameIndexDic.ContainsKey("c_HVD_1_ENABLE")) DOBytes[DONameIndexDic["c_HVD_1_ENABLE"]] = 1; if (DONameIndexDic.ContainsKey("c_HVD_2_ENABLE")) DOBytes[DONameIndexDic["c_HVD_2_ENABLE"]] = 1; //QDR if (AINameIndexDic.ContainsKey("r_QDRD1_WATER_LEVEL")) AIShorts[AINameIndexDic["r_QDRD1_WATER_LEVEL"]] = 0; if (AINameIndexDic.ContainsKey("r_QDRD2_WATER_LEVEL")) AIShorts[AINameIndexDic["r_QDRD2_WATER_LEVEL"]] = 0; if (AINameIndexDic.ContainsKey("r_QDRD3_WATER_LEVEL")) AIShorts[AINameIndexDic["r_QDRD3_WATER_LEVEL"]] = 0; if (AINameIndexDic.ContainsKey("r_QDRD4_WATER_LEVEL")) AIShorts[AINameIndexDic["r_QDRD4_WATER_LEVEL"]] = 0; //SRD if (AINameIndexDic.ContainsKey("r_SRD1_CHUCK_VACUUM_anlg")) AIShorts[AINameIndexDic["r_SRD1_CHUCK_VACUUM_anlg"]] = 15000; if (AINameIndexDic.ContainsKey("r_SRD2_CHUCK_VACUUM_anlg")) AIShorts[AINameIndexDic["r_SRD2_CHUCK_VACUUM_anlg"]] = 15000; if (DINameIndexDic.ContainsKey("r_SRD1_SHUTTER_OPEN")) DIBytes[DINameIndexDic["r_SRD1_SHUTTER_OPEN"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD1_SHUTTER_CLOSED")) DIBytes[DINameIndexDic["r_SRD1_SHUTTER_CLOSED"]] = 0; if (DINameIndexDic.ContainsKey("r_SRD2_SHUTTER_OPEN")) DIBytes[DINameIndexDic["r_SRD2_SHUTTER_OPEN"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD2_SHUTTER_CLOSED")) DIBytes[DINameIndexDic["r_SRD2_SHUTTER_CLOSED"]] = 0; if (DINameIndexDic.ContainsKey("r_SRD_FLUID_LEVEL")) DIBytes[DINameIndexDic["r_SRD_FLUID_LEVEL"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD1_CHUCK_VAC_OK")) DIBytes[DINameIndexDic["r_SRD1_CHUCK_VAC_OK"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD2_CHUCK_VAC_OK")) DIBytes[DINameIndexDic["r_SRD2_CHUCK_VAC_OK"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD1_150_FLIPPER1_OUT")) DIBytes[DINameIndexDic["r_SRD1_150_FLIPPER1_OUT"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD1_150_FLIPPER2_OUT")) DIBytes[DINameIndexDic["r_SRD1_150_FLIPPER2_OUT"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD1_150_FLIPPER3_OUT")) DIBytes[DINameIndexDic["r_SRD1_150_FLIPPER3_OUT"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD1_200_FLIPPER1_OUT")) DIBytes[DINameIndexDic["r_SRD1_200_FLIPPER1_OUT"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD1_200_FLIPPER2_OUT")) DIBytes[DINameIndexDic["r_SRD1_200_FLIPPER2_OUT"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD1_200_FLIPPER3_OUT")) DIBytes[DINameIndexDic["r_SRD1_200_FLIPPER3_OUT"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD2_150_FLIPPER1_OUT")) DIBytes[DINameIndexDic["r_SRD2_150_FLIPPER1_OUT"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD2_150_FLIPPER2_OUT")) DIBytes[DINameIndexDic["r_SRD2_150_FLIPPER2_OUT"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD2_150_FLIPPER3_OUT")) DIBytes[DINameIndexDic["r_SRD2_150_FLIPPER3_OUT"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD2_200_FLIPPER1_OUT")) DIBytes[DINameIndexDic["r_SRD2_200_FLIPPER1_OUT"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD2_200_FLIPPER2_OUT")) DIBytes[DINameIndexDic["r_SRD2_200_FLIPPER2_OUT"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD2_200_FLIPPER3_OUT")) DIBytes[DINameIndexDic["r_SRD2_200_FLIPPER3_OUT"]] = 1; if (DONameIndexDic.ContainsKey("c_SRD1_150_FLIPPERS_IN")) DOBytes[DONameIndexDic["c_SRD1_150_FLIPPERS_IN"]] = 1; if (DONameIndexDic.ContainsKey("c_SRD2_150_FLIPPERS_IN")) DOBytes[DONameIndexDic["c_SRD2_150_FLIPPERS_IN"]] = 1; if (DONameIndexDic.ContainsKey("c_SRD1_200_FLIPPERS_IN")) DOBytes[DONameIndexDic["c_SRD1_200_FLIPPERS_IN"]] = 1; if (DONameIndexDic.ContainsKey("c_SRD2_200_FLIPPERS_IN")) DOBytes[DONameIndexDic["c_SRD2_200_FLIPPERS_IN"]] = 1; if (DONameIndexDic.ContainsKey("c_SRD1_LIFT_UP")) DOBytes[DONameIndexDic["c_SRD1_LIFT_UP"]] = 1; if (DONameIndexDic.ContainsKey("c_SRD2_LIFT_UP")) DOBytes[DONameIndexDic["c_SRD2_LIFT_UP"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD1_WAFER_PRESENT")) DIBytes[DINameIndexDic["r_SRD1_WAFER_PRESENT"]] = 1; if (DINameIndexDic.ContainsKey("r_SRD2_WAFER_PRESENT")) DIBytes[DINameIndexDic["r_SRD2_WAFER_PRESENT"]] = 1; if (AINameIndexDic.ContainsKey("r_SRD_SUPPLY_WATER_PRESS")) AIShorts[AINameIndexDic["r_SRD_SUPPLY_WATER_PRESS"]] = 20000; //Metal if (AINameIndexDic.ContainsKey("r_PUMP4_FLOW")) AIShorts[AINameIndexDic["r_PUMP4_FLOW"]] = 3277; if (AINameIndexDic.ContainsKey("r_PUMP3_FLOW")) AIShorts[AINameIndexDic["r_PUMP3_FLOW"]] = 3277; if (AINameIndexDic.ContainsKey("r_PUMP2_FLOW")) AIShorts[AINameIndexDic["r_PUMP2_FLOW"]] = 3277; if (AINameIndexDic.ContainsKey("r_PUMP1_FLOW")) AIShorts[AINameIndexDic["r_PUMP1_FLOW"]] = 3277; //Facility if (AINameIndexDic.ContainsKey("r_DI_WATER_PRESSURE")) AIShorts[AINameIndexDic["r_DI_WATER_PRESSURE"]] = 12000; if (AINameIndexDic.ContainsKey("r_HCW_FLOW")) AIShorts[AINameIndexDic["r_HCW_FLOW"]] = 16300; if (AINameIndexDic.ContainsKey("r_N2_1B_PRESSURE")) AIShorts[AINameIndexDic["r_N2_1B_PRESSURE"]] = 5400; if (AINameIndexDic.ContainsKey("r_N2_1A_PRESSURE")) AIShorts[AINameIndexDic["r_N2_1A_PRESSURE"]] = 8900; if (AINameIndexDic.ContainsKey("r_N2_2B_PRESSURE")) AIShorts[AINameIndexDic["r_N2_2B_PRESSURE"]] = 5400; if (AINameIndexDic.ContainsKey("r_N2_2A_PRESSURE")) AIShorts[AINameIndexDic["r_N2_2A_PRESSURE"]] = 5400; if (AINameIndexDic.ContainsKey("r_SYSTEM_VACUUM")) AIShorts[AINameIndexDic["r_SYSTEM_VACUUM"]] = 3276; if (AINameIndexDic.ContainsKey("r_CDA_HIGH_PRESSURE")) AIShorts[AINameIndexDic["r_CDA_HIGH_PRESSURE"]] = 10000; if (AINameIndexDic.ContainsKey("r_CDA_LOW_PRESSURE")) AIShorts[AINameIndexDic["r_CDA_LOW_PRESSURE"]] = 10000; if (AINameIndexDic.ContainsKey("r_CDA_EXTERNAL_PRESSURE")) AIShorts[AINameIndexDic["r_CDA_EXTERNAL_PRESSURE"]] = 10000; if (AINameIndexDic.ContainsKey("r_pH3")) AIShorts[AINameIndexDic["r_pH3"]] = 15000; if (AINameIndexDic.ContainsKey("r_MBS3_FLOW")) AIShorts[AINameIndexDic["r_MBS3_FLOW"]] = 16000; } #region 公共方法 public void UpdataDOBytes(string name,int value) { if (OnDOVariableValueChanged != null) { OnDOVariableValueChanged(name); } if (DONameIndexDic.ContainsKey(name)) { if (DONameIndexDic[name] < DOBytes.Length) { DOBytes[DONameIndexDic[name]] = value == 0 ? (byte)0 : (byte)1; } } } public void UpdataDIBytes(string name, int value) { if (OnDIVariableValueChanged != null) { OnDIVariableValueChanged(name); } if (DINameIndexDic.ContainsKey(name)) { if (DINameIndexDic[name] < DIBytes.Length) { DIBytes[DINameIndexDic[name]] = value == 0 ? (byte)0 : (byte)1; } } } public void UpdataAOShorts(string name, int value) { if (OnAOVariableValueChanged != null) { OnAOVariableValueChanged(name); } if (AONameIndexDic.ContainsKey(name)) { string hexValue = value.ToString("X2"); try { short result = Convert.ToInt16(hexValue, 16); if (AONameIndexDic[name] < AOShorts.Length) { AOShorts[AONameIndexDic[name]] = result; } } catch (FormatException) { } } } public void UpdataAIShorts(string name, int value) { if (OnAIVariableValueChanged != null) { OnAIVariableValueChanged(name); } if (AINameIndexDic.ContainsKey(name)) { string hexValue = value.ToString("X2"); try { short result = Convert.ToInt16(hexValue, 16); if(AINameIndexDic[name] < AIShorts.Length) { AIShorts[AINameIndexDic[name]] = result; } } catch (FormatException) { } } } #endregion #region 功能方法 /// /// 将长度为8的二进制byte数组转成对应十六进制byte值(大端模式) /// /// /// public byte ConvertByteArrayToHex(byte[] byteArray) { byte result = 0; // 先将 byte 数组转换为二进制数 int binaryValue = 0; for (int i = 0; i < 8; i++) { binaryValue |= (byteArray[i] << (7 - i)); } // 逆转二进制数 int reversedValue = 0; for (int i = 0; i < 8; i++) { reversedValue |= ((binaryValue >> i) & 1) << (7 - i); } // 转换为十六进制byte if (byte.TryParse(reversedValue.ToString("X2"), System.Globalization.NumberStyles.HexNumber, null, out result)) { return result; } return 0; } /// /// 将short数组转成长度两倍的byte数组 /// /// /// private byte[] ConvertShortArrayToByteArray(short[] shortArray) { byte[] byteArray = new byte[shortArray.Length * 2]; for (int i = 0; i < shortArray.Length; i++) { byte[] tempBytes = BitConverter.GetBytes(shortArray[i]); Array.Reverse(tempBytes); Array.Copy(tempBytes, 0, byteArray, i * 2, 2); } return byteArray; } #endregion protected override void ProcessUnsplitMessage(byte[] data) { byte command = data[7]; if (command == 0x01) //读DO { short flag = byteTransform.TransInt16(data, 0); byte channel = data[6]; short startAddress = byteTransform.TransInt16(data, 8); short bitCount = byteTransform.TransInt16(data, 10); byte byteCount = (byte)(bitCount / 8 + 1); byte[] bytes = new byte[byteCount]; for(int i = 0; i < byteCount;i++) { byte[] tempbytes = new byte[8]; Array.Copy(DOBytes,8 * i, tempbytes, 0, 8); bytes[i] = ConvertByteArrayToHex(tempbytes); } OnWriteMessage(CreateReadDigitalResponse(flag, channel, command, byteCount, bytes)); return; } else if(command == 0x03)//读AO { short flag = byteTransform.TransInt16(data, 0); byte channel = data[6]; short startAddress = byteTransform.TransInt16(data, 8); short registerCount = byteTransform.TransInt16(data, 10); short[] shorts = new short[registerCount];//获取指定寄存器里的内容 Array.Copy(AOShorts, 0, shorts, 0, registerCount); byte[] bytes = new byte[registerCount * 2]; bytes = ConvertShortArrayToByteArray(shorts); //转入长度为shorts数组长度两倍的bytes数组中 OnWriteMessage(CreateReadAnalogyResponse(flag, channel, command, (byte)registerCount, bytes)); return; } else if (command == 0x02)//读DI { short flag = byteTransform.TransInt16(data, 0); byte channel = data[6]; short startAddress = byteTransform.TransInt16(data, 8); short bitCount = byteTransform.TransInt16(data, 10); byte byteCount = (byte)(bitCount / 8 + 1); byte[] bytes = new byte[byteCount]; for (int i = 0; i < byteCount; i++) { byte[] tempbytes = new byte[8]; Array.Copy(DIBytes, 8 * i, tempbytes, 0, 8); bytes[i] = ConvertByteArrayToHex(tempbytes); } OnWriteMessage(CreateReadDigitalResponse(flag, channel, command, byteCount, bytes)); return; } else if (command == 0x04)//读AI { short flag = byteTransform.TransInt16(data, 0); byte channel = data[6]; short startAddress = byteTransform.TransInt16(data, 8); short registerCount = byteTransform.TransInt16(data, 10); short[] shorts = new short[registerCount];//获取指定寄存器里的内容 Array.Copy(AIShorts, 0, shorts, 0, registerCount); byte[] bytes = new byte[registerCount * 2]; bytes = ConvertShortArrayToByteArray(shorts); //转入长度为shorts数组两倍的bytes数组中 OnWriteMessage(CreateReadAnalogyResponse(flag, channel, command, (byte)registerCount, bytes)); return; } else if (command == 0x05)//写DO { short startAddress = byteTransform.TransInt16(data, 8); if (startAddress > 0x03FF || startAddress < WRITE_DO_STARTADDRESS) { short flag = byteTransform.TransInt16(data, 0); byte channel = data[6]; OnWriteMessage(CreateError(flag, channel, command, 0x02)); //地址错误 return; } int position = startAddress - WRITE_DO_STARTADDRESS; bool status = data[10] == 0xFF ? true : false; lock (_writeDOLocker) { DOBytes[position] = status ? (byte)1 : (byte)0; } OnWriteMessage(data); //原消息返回 //触发Wago对应数据更新 UpdateDataCausedByWago(position, status); return; } else if (command == 0x06)//写AO { short startAddress = byteTransform.TransInt16(data, 8); if(startAddress > 0x02FF || startAddress < WRITE_AO_STARTADDRESS) { short flag = byteTransform.TransInt16(data, 0); byte channel = data[6]; OnWriteMessage(CreateError(flag, channel, command, 0x02)); //地址错误 return; } int position = startAddress - WRITE_AO_STARTADDRESS; short value = byteTransform.TransInt16(data, 10); lock (_writeAOLocker) { AOShorts[position] = value; } OnWriteMessage(data); //原消息返回 return; } else { short flag = byteTransform.TransInt16(data, 0); byte channel = data[6]; OnWriteMessage(CreateError(flag, channel, command, 0x01)); //指令错误 return; } } /// /// 回复读数字量 /// /// /// /// /// /// /// private byte[] CreateReadDigitalResponse(short flag, byte channel, byte command, byte byteCount, byte[] values) { byte[] bytes = new byte[7 + 2 + values.Length]; //回复字节长度,前面7个字节固定长度 + functionCode一个字节 + byteCount一个字节+values.length个字节 Array.Copy(byteTransform.GetBytes(flag), 0, bytes, 0, 2); bytes[2] = 0x00; bytes[3] = 0x00; short dataLength = (short)(3 + values.Length); Array.Copy(byteTransform.GetBytes(dataLength), 0, bytes, 4, 2); bytes[6] = channel; bytes[7] = command; bytes[8] = byteCount; Array.Copy(values, 0, bytes, 9, values.Length); return bytes; } /// /// 回复读模拟量 /// /// /// /// /// /// /// private byte[] CreateReadAnalogyResponse(short flag, byte channel, byte command, byte registerCount, byte[] values) { byte[] bytes = new byte[7 + 2 + 2 * registerCount]; //回复字节长度,前面7个字节固定长度 + functionCode一个字节 + byteCount一个字节+registerCount*2个字节(一个寄存器占两个字节) Array.Copy(byteTransform.GetBytes(flag), 0, bytes, 0, 2); bytes[2] = 0x00; bytes[3] = 0x00; short dataLength = (short)(3 + 2 * registerCount); Array.Copy(byteTransform.GetBytes(dataLength), 0, bytes, 4, 2); bytes[6] = channel; bytes[7] = command; bytes[8] = (byte)(2 * registerCount); Array.Copy(values, 0, bytes, 9, values.Length); return bytes; } /// /// 错误回复 /// /// /// /// /// /// private byte[] CreateError(short flag, byte channel, byte command, byte error) { byte[] bytes = new byte[9]; Array.Copy(byteTransform.GetBytes(flag), 0, bytes, 0, 2); bytes[2] = 0x00; bytes[3] = 0x00; bytes[4] = 0x00; bytes[5] = 0x03; bytes[6] = channel; bytes[7] = (byte)(command | 0x80); bytes[8] = error; return bytes; } /// /// loader 定时器 /// /// private bool OnTimer() { LeakTestSimulator(); return true; } /// /// Wago2定时器 /// /// private bool OnTimer1() { RinseWaterLevelSimulator(); PumpFlowSimulator(); return true; } /// /// Wago4定时器 /// /// private bool OnTimer3() { Pump1FlowSimulator(); return true; } #region 模拟方法 /// /// Loader LeakTest模拟 /// private void LeakTestSimulator() { if (DOBytes[DONameIndexDic["c_VACUUM_TEST"]] == 1 && _festoDataBuffer["FlowTestClamp"] && AIShorts[AINameIndexDic["r_LOADER_GasFlowSensor_FLOW"]] == 0) { AIShorts[AINameIndexDic["r_LOADER_GasFlowSensor_FLOW"]] = 15000; } else if (DOBytes[DONameIndexDic["c_VACUUM_TEST"]] == 0 && !_festoDataBuffer["FlowTestClamp"]) { AIShorts[AINameIndexDic["r_LOADER_GasFlowSensor_FLOW"]] = 0; } if (DOBytes[DONameIndexDic["c_VACUUM_TEST"]] == 1 && _festoDataBuffer["FlowTestClamp"] && AIShorts[AINameIndexDic["r_LOADER_GasFlowSensor_FLOW"]] > 3500) { AIShorts[AINameIndexDic["r_LOADER_GasFlowSensor_FLOW"]] -= 40; if (AIShorts[AINameIndexDic["r_LOADER_GasFlowSensor_FLOW"]] < 14000) { AIShorts[AINameIndexDic["r_LOADER_GasFlowSensor_FLOW"]] -= 140; } } } /// /// QDR水位模拟 /// private void RinseWaterLevelSimulator() { //QDR1 if (_rinse1FillValve && AIShorts[AINameIndexDic["r_QDRD1_WATER_LEVEL"]] < 25000) { AIShorts[AINameIndexDic["r_QDRD1_WATER_LEVEL"]] += 250; } if (_rinse1DumpValve && AIShorts[AINameIndexDic["r_QDRD1_WATER_LEVEL"]] > 3500) //快排 { AIShorts[AINameIndexDic["r_QDRD1_WATER_LEVEL"]] -= 350; } if (AIShorts[AINameIndexDic["r_QDRD1_WATER_LEVEL"]] > 3500)//慢排 { AIShorts[AINameIndexDic["r_QDRD1_WATER_LEVEL"]] -= 2; } //QDR2 if (_rinse2FillValve && AIShorts[AINameIndexDic["r_QDRD2_WATER_LEVEL"]] < 25000) { AIShorts[AINameIndexDic["r_QDRD2_WATER_LEVEL"]] += 250; } if (_rinse2DumpValve && AIShorts[AINameIndexDic["r_QDRD2_WATER_LEVEL"]] > 3500) { AIShorts[AINameIndexDic["r_QDRD2_WATER_LEVEL"]] -= 300; } if (AIShorts[AINameIndexDic["r_QDRD2_WATER_LEVEL"]] > 3500)//慢排 { AIShorts[AINameIndexDic["r_QDRD2_WATER_LEVEL"]] -= 2; } //QDR3 if (_rinse3FillValve && AIShorts[AINameIndexDic["r_QDRD3_WATER_LEVEL"]] < 25000) { AIShorts[AINameIndexDic["r_QDRD3_WATER_LEVEL"]] += 250; } if (_rinse3DumpValve && AIShorts[AINameIndexDic["r_QDRD3_WATER_LEVEL"]] > 3500) { AIShorts[AINameIndexDic["r_QDRD3_WATER_LEVEL"]] -= 300; } if (AIShorts[AINameIndexDic["r_QDRD3_WATER_LEVEL"]] > 3500)//慢排 { AIShorts[AINameIndexDic["r_QDRD3_WATER_LEVEL"]] -= 2; } //QDR4 if (_rinse4FillValve && AIShorts[AINameIndexDic["r_QDRD4_WATER_LEVEL"]] < 25000) { AIShorts[AINameIndexDic["r_QDRD4_WATER_LEVEL"]] += 250; } if (_rinse4DumpValve && AIShorts[AINameIndexDic["r_QDRD4_WATER_LEVEL"]] > 3500) { AIShorts[AINameIndexDic["r_QDRD4_WATER_LEVEL"]] -= 300; } if (AIShorts[AINameIndexDic["r_QDRD4_WATER_LEVEL"]] > 3500)//慢排 { AIShorts[AINameIndexDic["r_QDRD4_WATER_LEVEL"]] -= 2; } //reservoir1 pump flow AIShorts[AINameIndexDic["r_PUMP1_FLOW"]] = _reservoir1PumpOn ? (short)6000 : (short)3277; } /// /// metal 2/3/4 pump流量模拟 /// private void PumpFlowSimulator() { if (DOBytes[DONameIndexDic["c_METAL3_PUMP_ON"]] == 1) { AIShorts[AINameIndexDic["r_PUMP3_FLOW"]] = 6000; } else { AIShorts[AINameIndexDic["r_PUMP3_FLOW"]] = 3277; } if (DOBytes[DONameIndexDic["c_METAL2_PUMP_ON"]] == 1) { AIShorts[AINameIndexDic["r_PUMP2_FLOW"]] = 6000; } else { AIShorts[AINameIndexDic["r_PUMP2_FLOW"]] = 3277; } if (DOBytes[DONameIndexDic["c_METAL4_PUMP_ON"]] == 1) { AIShorts[AINameIndexDic["r_PUMP4_FLOW"]] = 6000; } else { AIShorts[AINameIndexDic["r_PUMP4_FLOW"]] = 3277; } } /// /// metal1 pump流量模拟 /// private void Pump1FlowSimulator() { if (DONameIndexDic.ContainsKey("c_METAL1_PUMP_ON") && DOBytes[DONameIndexDic["c_METAL1_PUMP_ON"]] == 1) { SimulatorCommManager.Instance.CheckDataChanged("c_METAL1_PUMP_ON",true,false); } else if (DONameIndexDic.ContainsKey("c_METAL1_PUMP_ON") && DOBytes[DONameIndexDic["c_METAL1_PUMP_ON"]] == 0) { SimulatorCommManager.Instance.CheckDataChanged("c_METAL1_PUMP_ON", false, false); } } #endregion } }