using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Xml; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Event; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.IOCore.Interlock; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using MECF.Framework.RT.Core.IoProviders; namespace MECF.Framework.Common.IOCore { public class IoManager : Singleton, IIoBuffer { private Dictionary _diMap = new(); private Dictionary _doMap = new(); private Dictionary _aiMap = new(); private Dictionary _aoMap = new(); private Dictionary> _diBuffer = new(); private Dictionary> _doBuffer = new(); private Dictionary> _aiBuffer = new(); private Dictionary> _aoBuffer = new(); private Dictionary> _aiBufferType = new(); private Dictionary> _aoBufferType = new(); private Dictionary> _diListPerPlc = new(); private Dictionary> _doListPerPlc = new(); private Dictionary> _aiListPerPlc = new(); private Dictionary> _aoListPerPlc = new(); private Dictionary> _ioItemList = new(); private PeriodicJob _monitorThread; /// /// 是否使用在模拟器中。 /// protected bool IsSimulator; public void Initialize(string interlockConfigFile, string daemonConfigFile = "") { if (!Singleton.Instance.Initialize(interlockConfigFile, _doMap, _diMap, _aiMap, _aoMap, out var reason1)) throw new Exception($"init {nameof(InterlockManager)} error: \r\n{reason1}"); /*if (!Singleton.Instance.Initialize(daemonConfigFile, _doMap, _diMap, _aiMap, _aoMap, out var reason2)) { //TODO 暂时允许不定义Daemon配置文件 // throw new Exception($"init {nameof(InterlockDaemonManager)} error: \r\n {reason2}"); LOG.Error($"init {nameof(InterlockDaemonManager)} error: \r\n{reason2}"); }*/ if(_monitorThread == null) _monitorThread = new PeriodicJob(200, OnTimer, "IOManager Monitor Thread", isStartNow: true); } private bool OnTimer() { try { Singleton.Instance.Monitor(); // Singleton.Instance.Monitor(); } catch (Exception ex) { LOG.Write(ex); } return true; } internal List> GetIONameList(string group, IOType ioType) { return null; } public bool CanSetDo(string doName, bool onOff, out string reason) { return Singleton.Instance.CanSetDo(doName, onOff, out reason); } public List GetDIList(string source) { return _diListPerPlc.TryGetValue(source, out var value) ? value : null; } public List GetDOList(string source) { return _doListPerPlc.TryGetValue(source, out var value) ? value : null; } public List GetAIList(string source) { return _aiListPerPlc.TryGetValue(source, out var value) ? value : null; } public List GetAOList(string source) { return _aoListPerPlc.TryGetValue(source, out var value) ? value : null; } public IoManager() { OP.Subscribe("System.SetDoValue", InvokeSetDo); OP.Subscribe("System.SetAoValue", InvokeSetAo); OP.Subscribe("System.SetAoValueFloat", InvokeSetAoFloat); OP.Subscribe("System.SetDoValueWithPrivoder", InvokeSetDoWithProvider); OP.Subscribe("System.SetAoValueWithPrivoder", InvokeSetAoWithPrivoder); OP.Subscribe("System.SetAiBuffer", InvokeSetAiBuffer); OP.Subscribe("System.SetDiBuffer", InvokeSetDiBuffer); } private bool InvokeSetDo(string arg1, object[] args) { var text = (string)args[0]; var flag = (bool)args[1]; if (!CanSetDo(text, flag, out var reason)) { EV.PostWarningLog("System", $"Can not set DO {text} to {flag}, {reason}"); return false; } var iO = GetIO(text); if (iO == null) { EV.PostWarningLog("System", $"Can not set DO {text} to {flag}, not defined do"); return false; } if (!iO.SetValue(flag, out reason)) { EV.PostWarningLog("System", $"Can not set DO {text} to {flag}, {reason}"); return false; } EV.PostInfoLog("System", $"Change DO {text} to {flag}"); return true; } private bool InvokeSetAo(string arg1, object[] args) { var text = (string)args[0]; var num = (short)args[1]; var iO = GetIO(text); if (iO == null) { EV.PostWarningLog("System", $"Can not set AO {text} to {num}, not defined do"); return false; } iO.Value = num; EV.PostInfoLog("System", $"Change AO {text} to {num}"); return true; } private bool InvokeSetAoFloat(string arg1, object[] args) { var text = (string)args[0]; var num = (float)args[1]; var iO = GetIO(text); if (iO == null) { EV.PostWarningLog("System", $"Can not set AO {text} to {num}, not defined"); return false; } iO.Value = num; EV.PostInfoLog("System", $"Change AO {text} to {num}"); return true; } private bool InvokeSetDoWithProvider(string arg1, object[] args) { var text = (string)args[0]; var num = (int)args[1]; var name = (string)args[2]; var flag = (bool)args[3]; if (!CanSetDo(name, flag, out var reason)) { EV.PostWarningLog("System", $"Can not set DO {text}.{name} to {flag}, {reason}"); return false; } var dOList = GetDOList(text); if (dOList == null) { EV.PostWarningLog("System", $"Can not set DO {text}.{name} to {flag}, {reason}"); return false; } var dOAccessor = dOList.FirstOrDefault((DOAccessor x) => x.Name == name); if (dOAccessor == null) { EV.PostWarningLog("System", $"Can not set DO {text}.{name} to {flag}, {reason}"); return false; } if (!dOAccessor.SetValue(flag, out reason)) { EV.PostWarningLog("System", $"Can not set DO {text}.{name} to {flag}, {reason}"); return false; } EV.PostInfoLog("System", $"Change DO {text}.{name} to {flag}"); return true; } private bool InvokeSetAiBuffer(string arg1, object[] args) { var source = (string)args[0]; var offset = (int)args[1]; var buffer = (float[])args[2]; SetAiBuffer(source, offset, buffer); return true; } private bool InvokeSetDiBuffer(string arg1, object[] args) { var source = (string)args[0]; var offset = (int)args[1]; var buffer = (bool[])args[2]; SetDiBuffer(source, offset, buffer); return true; } private bool InvokeSetAoWithPrivoder(string arg1, object[] args) { var text = (string)args[0]; var num = (int)args[1]; var name = (string)args[2]; var num2 = (float)args[3]; var text2 = ""; var aOList = GetAOList(text); if (aOList == null) { EV.PostWarningLog("System", $"Can not set AO {text}.{name} to {num2}, {text2}"); return false; } var aOAccessor = aOList.FirstOrDefault((AOAccessor x) => x.Name == name); if (aOAccessor == null) { EV.PostWarningLog("System", $"Can not set AO {text}.{name} to {num2}, {text2}"); return false; } aOAccessor.Value = (short)num2; EV.PostInfoLog("System", $"Change DO {text}.{name} to {num2}"); return true; } public T GetIO(string name) where T : class { if (typeof(T) == typeof(DIAccessor) && _diMap.TryGetValue(name, out var value)) { return value as T; } if (typeof(T) == typeof(DOAccessor) && _doMap.TryGetValue(name, out var value1)) { return value1 as T; } if (typeof(T) == typeof(AIAccessor) && _aiMap.TryGetValue(name, out var value2)) { return value2 as T; } if (typeof(T) == typeof(AOAccessor) && _aoMap.TryGetValue(name, out var value3)) { return value3 as T; } return null; } public Dictionary GetDiBuffer(string source) { if (_diBuffer.TryGetValue(source, out var buffer)) { return buffer; } return null; } public Dictionary GetDoBuffer(string source) { if (_doBuffer.TryGetValue(source, out var buffer)) { return buffer; } return null; } public Dictionary GetAiBuffer(string source) { return _aiBuffer.TryGetValue(source, out var f) ? f : null; } public Dictionary GetAoBuffer(string source) { return _aoBuffer.TryGetValue(source, out var buffer) ? buffer : null; } public void SetDiBuffer(string provider, int offset, bool[] data) { if (_diBuffer.ContainsKey(provider) && _diBuffer[provider].ContainsKey(offset)) { for (var i = 0; i < data.Length && i < _diBuffer[provider][offset].Length; i++) { _diBuffer[provider][offset][i] = data[i]; } } } public void SetDoBuffer(string provider, int offset, bool[] data) { if (_doBuffer.ContainsKey(provider) && _doBuffer[provider].ContainsKey(offset)) { for (var i = 0; i < data.Length && i < _doBuffer[provider][offset].Length; i++) { _doBuffer[provider][offset][i] = data[i]; } } } public void SetAiBuffer(string provider, int offset, float[] data, int skipSize = 0) { if (_aiBuffer.ContainsKey(provider) && _aiBuffer[provider].ContainsKey(offset)) { for (var i = 0; i < data.Length && i < _aiBuffer[provider][offset].Length; i++) { _aiBuffer[provider][offset][i + skipSize] = data[i]; } } } public void SetAoBuffer(string provider, int offset, float[] data, int bufferStartIndex = 0) { if (_aoBuffer.ContainsKey(provider) && _aoBuffer[provider].ContainsKey(offset)) { for (var i = 0; i < data.Length && i < _aoBuffer[provider][offset].Length; i++) { _aoBuffer[provider][offset][i] = data[i]; } } } public void SetBufferBlock(string provider, List lstBlocks) { foreach (var lstBlock in lstBlocks) { switch (lstBlock.Type) { case IoType.AI: if (!_aiBuffer.ContainsKey(provider)) { _aiBuffer[provider] = new IoDataCachePerOffset(provider); _aiBufferType[provider] = new IoDataCachePerOffset(provider); } if (!_aiBuffer[provider].ContainsKey(lstBlock.Offset)) { _aiBuffer[provider][lstBlock.Offset] = new float[lstBlock.Size]; _aiBufferType[provider][lstBlock.Offset] = lstBlock.AIOType; } break; case IoType.AO: if (!_aoBuffer.ContainsKey(provider)) { _aoBuffer[provider] = new IoDataCachePerOffset(provider); _aoBufferType[provider] = new IoDataCachePerOffset(provider); } if (!_aoBuffer[provider].ContainsKey(lstBlock.Offset)) { _aoBuffer[provider][lstBlock.Offset] = new float[lstBlock.Size]; _aoBufferType[provider][lstBlock.Offset] = lstBlock.AIOType; } break; case IoType.DI: if (!_diBuffer.ContainsKey(provider)) { _diBuffer[provider] = new IoDataCachePerOffset(provider); } if (!_diBuffer[provider].ContainsKey(lstBlock.Offset)) { _diBuffer[provider][lstBlock.Offset] = new bool[lstBlock.Size]; } break; case IoType.DO: if (!_doBuffer.ContainsKey(provider)) { _doBuffer[provider] = new IoDataCachePerOffset(provider); } if (!_doBuffer[provider].ContainsKey(lstBlock.Offset)) { _doBuffer[provider][lstBlock.Offset] = new bool[lstBlock.Size]; } break; } } } private List SubscribeDiData() { var list = new List(); foreach (var item2 in _diMap) { var item = new NotifiableIoItem { Address = item2.Value.Addr, Name = item2.Value.Name, Description = item2.Value.Description, Index = item2.Value.Index, BoolValue = item2.Value.Value, Provider = item2.Value.Provider, BlockOffset = item2.Value.BlockOffset, BlockIndex = item2.Value.Index, Visible = item2.Value.Visible }; list.Add(item); } return list; } private List SubscribeDoData() { var list = new List(); foreach (var item2 in _doMap) { var item = new NotifiableIoItem { Address = item2.Value.Addr, Name = item2.Value.Name, Description = item2.Value.Description, Index = item2.Value.Index, BoolValue = item2.Value.Value, Provider = item2.Value.Provider, BlockOffset = item2.Value.BlockOffset, BlockIndex = item2.Value.Index, Visible = item2.Value.Visible }; list.Add(item); } return list; } private List SubscribeAiData() { var list = new List(); foreach (var item2 in _aiMap) { var item = new NotifiableIoItem { Address = item2.Value.Addr, Name = item2.Value.Name, Description = item2.Value.Description, Index = item2.Value.Index, ShortValue = (short)item2.Value.Value, FloatValue = item2.Value.Value, Provider = item2.Value.Provider, BlockOffset = item2.Value.BlockOffset, BlockIndex = item2.Value.Index, Visible = item2.Value.Visible }; list.Add(item); } return list; } private List SubscribeAoData() { var list = new List(); foreach (var item2 in _aoMap) { var item = new NotifiableIoItem { Address = item2.Value.Addr, Name = item2.Value.Name, Description = item2.Value.Description, Index = item2.Value.Index, ShortValue = (short)item2.Value.Value, FloatValue = item2.Value.Value, Provider = item2.Value.Provider, BlockOffset = item2.Value.BlockOffset, BlockIndex = item2.Value.Index, Visible = item2.Value.Visible }; list.Add(item); } return list; } public void SetIoMap(string provider, int blockOffset, List ioList) { SubscribeIoItemList(provider); var flag = SC.GetConfigItem("System.IsIgnoreSaveDB")?.BoolValue ?? false; foreach (var accessor in ioList) { accessor.Provider = provider; accessor.BlockOffset = blockOffset; _diMap[accessor.Name] = accessor; if (!_diListPerPlc.ContainsKey(provider)) { _diListPerPlc[provider] = new List(); } _diListPerPlc[provider].Add(accessor); _ioItemList[provider + ".DIItemList"].Add(new NotifiableIoItem { Address = accessor.Addr, Name = accessor.Name, Description = accessor.Description, Index = accessor.Index, Provider = provider, BlockOffset = blockOffset, BlockIndex = accessor.BlockOffset, Visible = accessor.Visible }); if (!flag) { DATA.Subscribe("IO." + accessor.Name, () => accessor.Value); } } } public void SetIoMap(string provider, int blockOffset, List ioList) { SubscribeIoItemList(provider); var flag = SC.GetConfigItem("System.IsIgnoreSaveDB")?.BoolValue ?? false; foreach (var accessor in ioList) { accessor.Provider = provider; accessor.BlockOffset = blockOffset; _doMap[accessor.Name] = accessor; if (!_doListPerPlc.ContainsKey(provider)) { _doListPerPlc[provider] = new List(); } _doListPerPlc[provider].Add(accessor); _ioItemList[provider + ".DOItemList"].Add(new NotifiableIoItem { Address = accessor.Addr, Name = accessor.Name, Description = accessor.Description, Index = accessor.Index, Provider = provider, BlockOffset = blockOffset, BlockIndex = accessor.BlockOffset, Visible = accessor.Visible }); if (!flag) { DATA.Subscribe("IO." + accessor.Name, () => accessor.Value); } } } public void SetIoMap(string provider, int blockOffset, List ioList) { SubscribeIoItemList(provider); var flag = SC.GetConfigItem("System.IsIgnoreSaveDB")?.BoolValue ?? false; foreach (var accessor in ioList) { accessor.Provider = provider; accessor.BlockOffset = blockOffset; _aiMap[accessor.Name] = accessor; if (!_aiListPerPlc.ContainsKey(provider)) { _aiListPerPlc[provider] = new List(); } _aiListPerPlc[provider].Add(accessor); _ioItemList[provider + ".AIItemList"].Add(new NotifiableIoItem { Address = accessor.Addr, Name = accessor.Name, Description = accessor.Description, Index = accessor.Index, Provider = provider, BlockOffset = blockOffset, BlockIndex = accessor.BlockOffset, Visible = accessor.Visible }); if (!flag) { DATA.Subscribe("IO." + accessor.Name, () => accessor.Value); } } } public void SetIoMap(string provider, int blockOffset, List ioList) { SubscribeIoItemList(provider); var flag = SC.GetConfigItem("System.IsIgnoreSaveDB")?.BoolValue ?? false; foreach (var accessor in ioList) { accessor.Provider = provider; accessor.BlockOffset = blockOffset; _aoMap[accessor.Name] = accessor; if (!_aoListPerPlc.ContainsKey(provider)) { _aoListPerPlc[provider] = new List(); } _aoListPerPlc[provider].Add(accessor); _ioItemList[provider + ".AOItemList"].Add(new NotifiableIoItem { Address = accessor.Addr, Name = accessor.Name, Description = accessor.Description, Index = accessor.Index, Provider = provider, BlockOffset = blockOffset, BlockIndex = accessor.BlockOffset, Visible = accessor.Visible }); if (!flag) { DATA.Subscribe("IO." + accessor.Name, () => accessor.Value); } } } private void LoadIoDefinition(IIoDataCache cache, int blockOffset, XmlNodeList nodeList, IDictionary ioMap, IDictionary dictIoPerPlc, string module = "") where T: IIOAccessor { var isIgnoreSaveDb = SC.GetConfigItem("System.IsIgnoreSaveDB")?.BoolValue ?? false; foreach (var node in nodeList) { if (node is not XmlElement ioNode) continue; var ioIndexText = ioNode.GetAttribute("Index"); var ioBuffOffsetText = ioNode.GetAttribute("BufferOffset"); if (string.IsNullOrEmpty(ioBuffOffsetText)) ioBuffOffsetText = ioIndexText; var ioNameText = ioNode.GetAttribute("Name"); var ioAddrText = ioNode.GetAttribute("Addr"); var ioDescText = ioNode.GetAttribute("Description"); var visible = true; if (ioNode.HasAttribute("Visible")) { if (!bool.TryParse(ioNode.GetAttribute("Visible"), out visible)) visible = true; } var disableImmediateCache = false; if (ioNode.HasAttribute("DisImmCache")) { if (!bool.TryParse(ioNode.GetAttribute("DisImmCache"), out disableImmediateCache)) disableImmediateCache = false; } if (string.IsNullOrEmpty(ioNameText) || string.IsNullOrEmpty(ioIndexText) || string.IsNullOrEmpty(ioBuffOffsetText)) continue; ioNameText = ioNameText.Trim(); ioIndexText = ioIndexText.Trim(); ioBuffOffsetText = ioBuffOffsetText.Trim(); var ioNameWithModule = (string.IsNullOrEmpty(module) ? ioNameText : (module + "." + ioNameText)); if (!int.TryParse(ioIndexText, out var ioIndex) || !int.TryParse(ioBuffOffsetText, out var ioBuffOffset)) continue; if (cache == null) throw new Exception($"Not defined IO Data cache for Accessor {typeof(T)}."); var provider = cache.ProviderName; var accessor = (IIOAccessor)Activator.CreateInstance(typeof(T), ioNameWithModule, ioBuffOffset, ioAddrText, IsSimulator, disableImmediateCache); accessor.IoTableIndex = ioIndex; accessor.Provider = provider; accessor.BlockOffset = blockOffset; accessor.Description = ioDescText; accessor.Visible = visible; accessor.BindBuffer(cache[blockOffset]); ioMap.Add(ioNameWithModule, accessor); if (dictIoPerPlc.Contains(provider) == false) dictIoPerPlc[provider] = new List(); ((IList)dictIoPerPlc[provider]).Add(accessor); _ioItemList[provider + $".{accessor.Type}ItemList"].Add(new NotifiableIoItem { Address = ioAddrText, Name = ioNameWithModule, Description = ioDescText, Index = ioIndex, Provider = provider, BlockOffset = blockOffset, BlockIndex = ioIndex, Visible = visible }); if (!isIgnoreSaveDb) DATA.Subscribe("IO." + ioNameWithModule, () => accessor.NonTypedValue); } } public void SetIoMap(string provider, int blockOffset, string xmlPathFile, string module = "") { SubscribeIoItemList(provider); var xmlDocument = new XmlDocument(); xmlDocument.Load(xmlPathFile); var xmlNodeDiDefs = xmlDocument.SelectNodes("IO_DEFINE/Dig_In/DI_ITEM"); LoadIoDefinition(_diBuffer[provider], blockOffset, xmlNodeDiDefs, _diMap, _diListPerPlc, module); var xmlNodeDoDefs = xmlDocument.SelectNodes("IO_DEFINE/Dig_Out/DO_ITEM"); LoadIoDefinition(_doBuffer[provider], blockOffset, xmlNodeDoDefs, _doMap, _doListPerPlc, module); var xmlNodeAoDefs = xmlDocument.SelectNodes("IO_DEFINE/Ana_Out/AO_ITEM"); LoadIoDefinition(_aoBuffer[provider], blockOffset, xmlNodeAoDefs, _aoMap, _aoListPerPlc, module); var xmlNodeAiDefs = xmlDocument.SelectNodes("IO_DEFINE/Ana_In/AI_ITEM"); LoadIoDefinition(_aiBuffer[provider], blockOffset, xmlNodeAiDefs, _aiMap, _aiListPerPlc, module); } public void SetIoMap(string provider, Dictionary ioMappingPathFile) { foreach (var item in ioMappingPathFile) { SetIoMap(provider, item.Key, item.Value); } DATA.Subscribe(provider, "DIList", SubscribeDiData); DATA.Subscribe(provider, "DOList", SubscribeDoData); DATA.Subscribe(provider, "AIList", SubscribeAiData); DATA.Subscribe(provider, "AOList", SubscribeAoData); } public void SetIoMapByModule(string provider, int offset, string ioMappingPathFile, string module) { SetIoMap(provider, offset, ioMappingPathFile, module); DATA.Subscribe(provider, "DIList", SubscribeDiData); DATA.Subscribe(provider, "DOList", SubscribeDoData); DATA.Subscribe(provider, "AIList", SubscribeAiData); DATA.Subscribe(provider, "AOList", SubscribeAoData); } private void SubscribeIoItemList(string provider) { var diKey = provider + ".DIItemList"; if (!_ioItemList.ContainsKey(diKey)) { _ioItemList[diKey] = []; DATA.Subscribe(diKey, () => _ioItemList[diKey]); } var doKey = provider + ".DOItemList"; if (!_ioItemList.ContainsKey(doKey)) { _ioItemList[doKey] = []; DATA.Subscribe(doKey, () => _ioItemList[doKey]); } var aiKey = provider + ".AIItemList"; if (!_ioItemList.ContainsKey(aiKey)) { _ioItemList[aiKey] = []; DATA.Subscribe(aiKey, () => _ioItemList[aiKey]); } var aoKey = provider + ".AOItemList"; if (!_ioItemList.ContainsKey(aoKey)) { _ioItemList[aoKey] = []; DATA.Subscribe(aoKey, () => _ioItemList[aoKey]); } } } }