using Aitex.Common.Util; using Aitex.Core.RT.Log; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using DocumentFormat.OpenXml.Wordprocessing; using MECF.Framework.Common.Device.Festo; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.IOCore; using MECF.Framework.Common.TwinCat; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; namespace MECF.Framework.Common.Device.Wago { public class WagoControllerCfgManager : Singleton { #region 常量 private const string STOPCODE = "StopCode"; private const string REFERENCE_POSITION = "ReferencePosition"; private const string TORQUE = "Torque"; private const string VELOCITY = "Velocity"; private const string POSITION_ERROR = "PositionError"; private const string AUXILIARY_POSITION = "AuxiliaryPosition"; #endregion #region 内部变量 /// /// do--Modbus设备字典(key-DO名称,value-Modbus设备) /// private Dictionary _ioModbusDictionary = new Dictionary(); /// /// 索引DI名称字典(key-DI索引,value-DI名称) /// private Dictionary _indexDIDictionary = new Dictionary(); /// /// 索引DO名称字典(key-DI索引,value-DO名称) /// private Dictionary _indexDODictionary = new Dictionary(); /// /// 索引AI名称字典(key-DI索引,value-AI名称) /// private Dictionary _indexAIDictionary = new Dictionary(); /// /// 索引AO名称字典(key-DI索引,value-AO名称) /// private Dictionary _indexAODictionary = new Dictionary(); /// /// DI名称索引字典(key-DI名称,value-(byte数组索引,bit索引)) /// private Dictionary _diNameIndexDictionary = new Dictionary(); /// /// DO名称索引字典(key-DO名称,value-(byte数组索引,bit索引)) /// private Dictionary _doNameIndexDictionary = new Dictionary(); /// /// 名称数据数组字典(key-festo名称,value-每个festo的byte数组) /// private ConcurrentDictionary _moduleDatasDictionary = new ConcurrentDictionary(); /// /// 模块DI字典(key-模块,value-DI名称集合) /// private Dictionary> _moduleDINameListDictionary = new Dictionary>(); /// /// 模块DO字典(key-模块,value-DO名称集合) /// private Dictionary> _moduleDONameListDictionary = new Dictionary>(); /// /// DO-模块字典(key-DO名称,value-模块名称) /// private Dictionary _doModuleDictionary = new Dictionary(); /// /// 模块AI字典(key-模块,value-AI名称集合) /// private Dictionary> _moduleAIListDictionary = new Dictionary>(); /// /// 模块AO字典(key-模块,value-AO名称集合) /// private Dictionary> _moduleAOListDictionary = new Dictionary>(); /// /// DO字典(key-DO名称,value-DO对象) /// private Dictionary _moduleNameDODictionary = new Dictionary(); /// /// AO字典(key-AO名称,value-AO对象) /// private Dictionary _moduleNameAODictionary = new Dictionary(); /// /// 模块名称数值字典(key-模块名称,value-数值) /// private ConcurrentDictionary _moduleNameValueDictionary = new ConcurrentDictionary(); #endregion /// /// 初始化 /// public void Initialize(List lst) { bool isSimulate = SC.GetValue("System.IsSimulatorMode"); string xmlPath = ""; try { if (isSimulate) { xmlPath = PathManager.GetCfgDir() + "Devices\\WagoControllerCfg-Simulator.xml"; } else { xmlPath = PathManager.GetCfgDir() + "Devices\\WagoControllerCfg.xml"; } WagoControllerCfg cfg = CustomXmlSerializer.Deserialize(new FileInfo(xmlPath)); if (cfg != null) { foreach (var config in cfg.WagoDeviceConfigs) { WagoModbusDevice modbusDevice = new WagoModbusDevice(config.Module, config.IpAddress, config.Port, (byte)config.Channel); modbusDevice.ReceiveTimeout = config.RecvTimeout; modbusDevice.SendTimeout = config.SendTimeout; InitializeWagoDeviceConfig(config, modbusDevice, lst); } } } catch { LOG.WriteLog(eEvent.ERR_GALIL, "Galil", "Load galil xml failed"); } } /// /// 初始化设备 /// /// private void InitializeWagoDeviceConfig(WagoDeviceConfig deviceConfig,WagoModbusDevice modbusDevice,List lst) { //DI ushort diCount = (ushort)deviceConfig.WagoDigIn.WagoDIs.Count; ushort diStartAddress = (ushort)deviceConfig.WagoDigIn.WagoDIs[0].Address; List diLst = new List(); List diAddressLst = new List(); int tmpCount = -1; for (int i = 0; i < deviceConfig.WagoDigIn.WagoDIs.Count; i++) { WagoDI item = deviceConfig.WagoDigIn.WagoDIs[i]; _indexDIDictionary[i] = item.Name; if (!diAddressLst.Contains(item.Address)) { diAddressLst.Add(item.Address); tmpCount++; _diNameIndexDictionary[item.Name] = (tmpCount, item.Bit); } else { _diNameIndexDictionary[item.Name] = (tmpCount, item.Bit); } diLst.Add(item.Name); } _moduleDINameListDictionary[deviceConfig.Module] = diLst; //DO ushort doCount = (ushort)deviceConfig.WagoDigOut.WagoDOs.Count; ushort doStartAddress = (ushort)deviceConfig.WagoDigOut.WagoDOs[0].Address; List doList = new List(); List doAddressLst = new List(); int count = -1; for (int i = 0; i < deviceConfig.WagoDigOut.WagoDOs.Count; i++) { WagoDO item = deviceConfig.WagoDigOut.WagoDOs[i]; _ioModbusDictionary[item.Name] = modbusDevice; _indexDODictionary[i] = item.Name; if (!doAddressLst.Contains(item.Address)) { doAddressLst.Add(item.Address); count++; _doNameIndexDictionary[item.Name] = (count, item.Bit); } else { _doNameIndexDictionary[item.Name] = (count, item.Bit); } doList.Add(item.Name); _moduleNameDODictionary[item.Name] = item; _doModuleDictionary[item.Name] = deviceConfig.Module; } _moduleDONameListDictionary[deviceConfig.Module] = doList; if (doAddressLst.Count > 0) { _moduleDatasDictionary[deviceConfig.Module] = new byte[doAddressLst.Count]; } //AI ushort aiCount = (ushort)deviceConfig.WagoAnoIn.WagoAIs.Count; ushort aiStartAddress = (ushort)deviceConfig.WagoAnoIn.WagoAIs[0].Address; for (int i = 0; i < deviceConfig.WagoAnoIn.WagoAIs.Count; i++) { WagoAI item = deviceConfig.WagoAnoIn.WagoAIs[i]; _indexAIDictionary[i] = item.Name; if (!string.IsNullOrEmpty(item.Scaling)) { ScalingManager.Instance.Initialize(item.Name, item.Scaling); } } _moduleAIListDictionary[deviceConfig.Module] = deviceConfig.WagoAnoIn.WagoAIs; //AO ushort aoCount = (ushort)deviceConfig.WagoAnoOut.WagoAOs.Count; ushort aoStartAddress = (ushort)deviceConfig.WagoAnoOut.WagoAOs[0].Address; for (int i = 0; i < deviceConfig.WagoAnoIn.WagoAIs.Count; i++) { WagoAO item = deviceConfig.WagoAnoOut.WagoAOs[i]; _ioModbusDictionary[item.Name] = modbusDevice; _indexAODictionary[i] = item.Name; if (!string.IsNullOrEmpty(item.Scaling)) { ScalingManager.Instance.Initialize(item.Name, item.Scaling); } _moduleNameAODictionary[item.Name] = item; } _moduleAOListDictionary[deviceConfig.Module] = deviceConfig.WagoAnoOut.WagoAOs; modbusDevice.Initialize(diCount, diStartAddress, doCount, doStartAddress, aiCount, aiStartAddress, aoCount, aoStartAddress); } /// /// 更新DI数组 /// /// /// public void UpdateWagoDIData(string name, bool[] datas) { if (_moduleDINameListDictionary.ContainsKey(name)) { List diLst = _moduleDINameListDictionary[name]; UpdateWagoDigitalData(diLst, _diNameIndexDictionary, datas); } } /// /// 更新DO数组 /// /// /// public void UpdateWagoDOData(string name, bool[] datas) { if (_moduleDONameListDictionary.ContainsKey(name)) { UpdateWagoDigitalData(_moduleDONameListDictionary[name], _doNameIndexDictionary, datas); } } /// /// 更新Wago数字数值 /// /// /// /// private void UpdateWagoDigitalData(List lst,Dictionary dic, bool[] datas) { foreach (var item in lst) { if (!dic.ContainsKey(item)) { continue; } var varIndex = dic[item]; int boolIndex = varIndex.Item1 * 8 + varIndex.Item2; if (boolIndex >= datas.Length) { continue; } bool value = datas[boolIndex]; if (!_moduleNameValueDictionary.ContainsKey(item)) { _moduleNameValueDictionary[item] = value; IOModuleManager.Instance.UpdateIoValue(item, value); } else { if (value != (bool)_moduleNameValueDictionary[item]) { _moduleNameValueDictionary[item] = value; IOModuleManager.Instance.UpdateIoValue(item, value); } } } } /// /// 更新AI数组 /// /// /// public void UpdateWagoAIData(string name, byte[] datas) { if (_moduleAIListDictionary.ContainsKey(name)) { List wagoAIs = _moduleAIListDictionary[name]; for(int i = 0; i < wagoAIs.Count; i++) { WagoAI wagoAI = wagoAIs[i]; if (i * 2 >= datas.Length) { break; } UpdateWagoAnalogData(wagoAI.Name, wagoAI.Scaling, wagoAI.DataType, datas, i); } } } /// /// 更新AO数组 /// /// /// public void UpdateWagoAOData(string name, byte[] datas) { if (_moduleAOListDictionary.ContainsKey(name)) { List wagoAOs = _moduleAOListDictionary[name]; for (int i = 0; i < wagoAOs.Count; i++) { WagoAO wagoAO = wagoAOs[i]; if (i * 2 >= datas.Length) { break; } UpdateWagoAnalogData(wagoAO.Name, wagoAO.Scaling, wagoAO.DataType, datas, i); } } } /// /// 更新模拟量数据 /// /// /// /// /// /// private void UpdateWagoAnalogData(string moduleName,string scaling,string dataType, byte[] datas,int index) { object value = null; if (dataType == "short") { value = BitConverter.ToInt16(datas, index * 2); } else { value = BitConverter.ToUInt16(datas, index * 2); } if (!string.IsNullOrEmpty(scaling)) { value = ScalingManager.Instance.CalculateValueByTwincatVariable(moduleName, (double)value); } if (!_moduleNameValueDictionary.ContainsKey(moduleName)) { _moduleNameValueDictionary[moduleName] = value; IOModuleManager.Instance.UpdateIoValue(moduleName, value); } else { if (value.ToString() != _moduleNameValueDictionary[moduleName].ToString()) { _moduleNameValueDictionary[moduleName] = value; IOModuleManager.Instance.UpdateIoValue(moduleName, value); } } } /// /// 写入IO数值 /// /// /// /// public bool WriteIOValue(string ioName,object value) { if (_moduleNameDODictionary.ContainsKey(ioName)) { return SetDoValue(ioName, (bool)value); } else if (_moduleNameAODictionary.ContainsKey(ioName)) { return SetAoValue(ioName, (double)value); } else { LOG.WriteLog(eEvent.ERR_WAGO, "Wago", $"{ioName} object is null"); return false; } } /// /// 设置DO数值 /// /// /// /// private bool SetDoValue(string doName, bool value) { if (!_moduleNameDODictionary.ContainsKey(doName)) { LOG.WriteLog(eEvent.ERR_WAGO, "Wago", $"{doName} object is null"); return false; } WagoDO wagoDO = _moduleNameDODictionary[doName]; if (!_ioModbusDictionary.ContainsKey(doName)) { LOG.WriteLog(eEvent.ERR_WAGO, "Wago", $"{doName} wago device is null"); return false; } if (!_doNameIndexDictionary.ContainsKey(doName)) { LOG.WriteLog(eEvent.ERR_WAGO, "Wago", $"{doName} does not have index dictionary"); return false; } var var=_doNameIndexDictionary[doName]; WagoModbusDevice device = _ioModbusDictionary[doName]; if (!_doModuleDictionary.ContainsKey(doName)) { LOG.WriteLog(eEvent.ERR_WAGO, "Wago", $"{doName} does not have module dictionary"); return false; } string module = _doModuleDictionary[doName]; if (!_moduleDatasDictionary.ContainsKey(module)) { LOG.WriteLog(eEvent.ERR_WAGO, "Wago", $"{module} does not have datas dictionary"); return false; } byte[] datas = _moduleDatasDictionary[module]; if (var.Item1 >= datas.Length) { LOG.WriteLog(eEvent.ERR_WAGO, "Wago", $"{doName} {var.Item1} is over datas length"); return false; } try { bool lastValue = wagoDO.Invert ? !value : value; byte festoValue = GenerateWagoData(wagoDO, datas[var.Item1], lastValue); bool result = device.WriteDOValue((ushort)wagoDO.Address, festoValue); if (result) { LOG.WriteLog(eEvent.INFO_WAGO, "Wago", $"{doName} write {value} success"); } else { LOG.WriteLog(eEvent.ERR_WAGO, "Wago", $"{doName} write {value} failed"); } return result; } catch (Exception ex) { LOG.WriteLog(eEvent.ERR_WAGO, "Wago", $"write {doName} value {value} {ex.Message}"); return false; } } /// /// 构建Festo字节数值 /// /// /// /// /// private byte GenerateWagoData(WagoDO wagoDO, byte source, bool value) { int bit = wagoDO.Bit; bool sourceBit = (source >> bit & 0x01) == 1; if (sourceBit == value) { return source; } else { if (value) { return (byte)(source + Math.Pow(2, bit)); } else { return (byte)(source - Math.Pow(2, bit)); } } } /// /// 设置DO数值 /// /// /// /// public bool SetAoValue(string aoName, double value) { if (!_moduleNameAODictionary.ContainsKey(aoName)) { LOG.WriteLog(eEvent.ERR_WAGO, "Wago", $"{aoName} object is null"); return false; } WagoAO wagoAO = _moduleNameAODictionary[aoName]; if (!_ioModbusDictionary.ContainsKey(aoName)) { LOG.WriteLog(eEvent.ERR_WAGO, "Wago", $"{aoName} wago device is null"); return false; } WagoModbusDevice device = _ioModbusDictionary[aoName]; try { byte[] writeByts = null; if (!string.IsNullOrEmpty(wagoAO.Scaling)) { var var=ScalingManager.Instance.CalculateTwincatValueByInput(aoName, value); if (var.Item1) { if (wagoAO.DataType == "short") { writeByts = BitConverter.GetBytes((short)var.Item2); } else { writeByts = BitConverter.GetBytes((ushort)var.Item2); } } } bool result = device.WriteAOValue((ushort)wagoAO.Address, writeByts); if (result) { LOG.WriteLog(eEvent.INFO_WAGO, "Wago", $"{aoName} write {value} success"); } else { LOG.WriteLog(eEvent.ERR_WAGO, "Wago", $"{aoName} write {value} failed"); } return result; } catch (Exception ex) { LOG.WriteLog(eEvent.ERR_WAGO, "Wago", $"write {aoName} value {value} {ex.Message}"); return false; } } } }