2023-04-13 11:51:03 +08:00
|
|
|
using System;
|
2023-12-18 16:39:16 +08:00
|
|
|
using System.Collections;
|
2023-04-13 11:51:03 +08:00
|
|
|
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;
|
2023-08-17 09:43:24 +08:00
|
|
|
using Aitex.Core.RT.IOCore.Interlock;
|
2023-04-13 11:51:03 +08:00
|
|
|
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<IoManager>, IIoBuffer
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
private Dictionary<string, DIAccessor> _diMap = new();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private Dictionary<string, DOAccessor> _doMap = new();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private Dictionary<string, AIAccessor> _aiMap = new();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private Dictionary<string, AOAccessor> _aoMap = new();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private Dictionary<string, IoDataCachePerOffset<bool[]>> _diBuffer = new();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private Dictionary<string, IoDataCachePerOffset<bool[]>> _doBuffer = new();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private Dictionary<string, IoDataCachePerOffset<float[]>> _aiBuffer = new();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private Dictionary<string, IoDataCachePerOffset<float[]>> _aoBuffer = new();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private Dictionary<string, IoDataCachePerOffset<Type>> _aiBufferType = new();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private Dictionary<string, IoDataCachePerOffset<Type>> _aoBufferType = new();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private Dictionary<string, List<DIAccessor>> _diListPerPlc = new();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private Dictionary<string, List<DOAccessor>> _doListPerPlc = new();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private Dictionary<string, List<AIAccessor>> _aiListPerPlc = new();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private Dictionary<string, List<AOAccessor>> _aoListPerPlc = new();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private Dictionary<string, List<NotifiableIoItem>> _ioItemList = new();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
private PeriodicJob _monitorThread;
|
2023-08-10 16:44:46 +08:00
|
|
|
|
2024-01-07 11:29:22 +08:00
|
|
|
/// <summary>
|
|
|
|
/// 是否使用在模拟器中。
|
|
|
|
/// </summary>
|
|
|
|
protected bool IsSimulator;
|
|
|
|
|
2023-08-31 11:40:28 +08:00
|
|
|
public void Initialize(string interlockConfigFile, string daemonConfigFile = "")
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-08-17 00:39:12 +08:00
|
|
|
if (!Singleton<InterlockManager>.Instance.Initialize(interlockConfigFile, _doMap, _diMap, _aiMap, _aoMap,
|
2023-08-10 16:44:46 +08:00
|
|
|
out var reason1))
|
2023-08-15 15:36:38 +08:00
|
|
|
throw new Exception($"init {nameof(InterlockManager)} error: \r\n{reason1}");
|
2023-08-10 16:44:46 +08:00
|
|
|
|
2023-10-25 16:40:36 +08:00
|
|
|
/*if (!Singleton<InterlockDaemonManager>.Instance.Initialize(daemonConfigFile, _doMap, _diMap, _aiMap, _aoMap,
|
2023-08-10 16:44:46 +08:00
|
|
|
out var reason2))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-08-10 16:44:46 +08:00
|
|
|
//TODO 暂时允许不定义Daemon配置文件
|
|
|
|
// throw new Exception($"init {nameof(InterlockDaemonManager)} error: \r\n {reason2}");
|
|
|
|
|
2023-08-15 15:36:38 +08:00
|
|
|
LOG.Error($"init {nameof(InterlockDaemonManager)} error: \r\n{reason2}");
|
2023-08-31 11:40:28 +08:00
|
|
|
}*/
|
2023-10-25 16:40:36 +08:00
|
|
|
|
|
|
|
if(_monitorThread == null)
|
|
|
|
_monitorThread = new PeriodicJob(200, OnTimer, "IOManager Monitor Thread", isStartNow: true);
|
|
|
|
}
|
2023-08-10 16:44:46 +08:00
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
private bool OnTimer()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
Singleton<InterlockManager>.Instance.Monitor();
|
2023-08-31 11:40:28 +08:00
|
|
|
// Singleton<InterlockDaemonManager>.Instance.Monitor();
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
|
|
|
catch (Exception ex)
|
|
|
|
{
|
|
|
|
LOG.Write(ex);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal List<Tuple<int, int, string>> GetIONameList(string group, IOType ioType)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool CanSetDo(string doName, bool onOff, out string reason)
|
|
|
|
{
|
|
|
|
return Singleton<InterlockManager>.Instance.CanSetDo(doName, onOff, out reason);
|
|
|
|
}
|
|
|
|
|
|
|
|
public List<DIAccessor> GetDIList(string source)
|
2023-12-18 16:39:16 +08:00
|
|
|
{
|
|
|
|
return _diListPerPlc.TryGetValue(source, out var value) ? value : null;
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
public List<DOAccessor> GetDOList(string source)
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
return _doListPerPlc.TryGetValue(source, out var value) ? value : null;
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public List<AIAccessor> GetAIList(string source)
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
return _aiListPerPlc.TryGetValue(source, out var value) ? value : null;
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public List<AOAccessor> GetAOList(string source)
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
return _aoListPerPlc.TryGetValue(source, out var value) ? value : null;
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public IoManager()
|
|
|
|
{
|
|
|
|
OP.Subscribe("System.SetDoValue", InvokeSetDo);
|
|
|
|
OP.Subscribe("System.SetAoValue", InvokeSetAo);
|
|
|
|
OP.Subscribe("System.SetAoValueFloat", InvokeSetAoFloat);
|
2023-12-18 16:39:16 +08:00
|
|
|
OP.Subscribe("System.SetDoValueWithPrivoder", InvokeSetDoWithProvider);
|
2023-04-13 11:51:03 +08:00
|
|
|
OP.Subscribe("System.SetAoValueWithPrivoder", InvokeSetAoWithPrivoder);
|
|
|
|
OP.Subscribe("System.SetAiBuffer", InvokeSetAiBuffer);
|
|
|
|
OP.Subscribe("System.SetDiBuffer", InvokeSetDiBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool InvokeSetDo(string arg1, object[] args)
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
var text = (string)args[0];
|
|
|
|
var flag = (bool)args[1];
|
2023-04-13 11:51:03 +08:00
|
|
|
if (!CanSetDo(text, flag, out var reason))
|
|
|
|
{
|
|
|
|
EV.PostWarningLog("System", $"Can not set DO {text} to {flag}, {reason}");
|
|
|
|
return false;
|
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
var iO = GetIO<DOAccessor>(text);
|
2023-04-13 11:51:03 +08:00
|
|
|
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)
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
var text = (string)args[0];
|
|
|
|
var num = (short)args[1];
|
|
|
|
var iO = GetIO<AOAccessor>(text);
|
2023-04-13 11:51:03 +08:00
|
|
|
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)
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
var text = (string)args[0];
|
|
|
|
var num = (float)args[1];
|
|
|
|
var iO = GetIO<AOAccessor>(text);
|
2023-04-13 11:51:03 +08:00
|
|
|
if (iO == null)
|
|
|
|
{
|
|
|
|
EV.PostWarningLog("System", $"Can not set AO {text} to {num}, not defined");
|
|
|
|
return false;
|
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
iO.Value = num;
|
2023-04-13 11:51:03 +08:00
|
|
|
EV.PostInfoLog("System", $"Change AO {text} to {num}");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private bool InvokeSetDoWithProvider(string arg1, object[] args)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
var text = (string)args[0];
|
|
|
|
var num = (int)args[1];
|
|
|
|
var name = (string)args[2];
|
|
|
|
var flag = (bool)args[3];
|
2023-04-13 11:51:03 +08:00
|
|
|
if (!CanSetDo(name, flag, out var reason))
|
|
|
|
{
|
|
|
|
EV.PostWarningLog("System", $"Can not set DO {text}.{name} to {flag}, {reason}");
|
|
|
|
return false;
|
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
var dOList = GetDOList(text);
|
2023-04-13 11:51:03 +08:00
|
|
|
if (dOList == null)
|
|
|
|
{
|
|
|
|
EV.PostWarningLog("System", $"Can not set DO {text}.{name} to {flag}, {reason}");
|
|
|
|
return false;
|
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
var dOAccessor = dOList.FirstOrDefault((DOAccessor x) => x.Name == name);
|
2023-04-13 11:51:03 +08:00
|
|
|
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)
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
var source = (string)args[0];
|
|
|
|
var offset = (int)args[1];
|
|
|
|
var buffer = (float[])args[2];
|
2023-04-13 11:51:03 +08:00
|
|
|
SetAiBuffer(source, offset, buffer);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool InvokeSetDiBuffer(string arg1, object[] args)
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
var source = (string)args[0];
|
|
|
|
var offset = (int)args[1];
|
|
|
|
var buffer = (bool[])args[2];
|
2023-04-13 11:51:03 +08:00
|
|
|
SetDiBuffer(source, offset, buffer);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool InvokeSetAoWithPrivoder(string arg1, object[] args)
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
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);
|
2023-04-13 11:51:03 +08:00
|
|
|
if (aOList == null)
|
|
|
|
{
|
|
|
|
EV.PostWarningLog("System", $"Can not set AO {text}.{name} to {num2}, {text2}");
|
|
|
|
return false;
|
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
var aOAccessor = aOList.FirstOrDefault((AOAccessor x) => x.Name == name);
|
2023-04-13 11:51:03 +08:00
|
|
|
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<T>(string name) where T : class
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
if (typeof(T) == typeof(DIAccessor) && _diMap.TryGetValue(name, out var value))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
return value as T;
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
if (typeof(T) == typeof(DOAccessor) && _doMap.TryGetValue(name, out var value1))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
return value1 as T;
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
if (typeof(T) == typeof(AIAccessor) && _aiMap.TryGetValue(name, out var value2))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
return value2 as T;
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
if (typeof(T) == typeof(AOAccessor) && _aoMap.TryGetValue(name, out var value3))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
return value3 as T;
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Dictionary<int, bool[]> GetDiBuffer(string source)
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
if (_diBuffer.TryGetValue(source, out var buffer))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
return buffer;
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Dictionary<int, bool[]> GetDoBuffer(string source)
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
if (_doBuffer.TryGetValue(source, out var buffer))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
return buffer;
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
|
|
|
|
public Dictionary<int, float[]> GetAiBuffer(string source)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
return _aiBuffer.TryGetValue(source, out var f) ? f : null;
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
public Dictionary<int, float[]> GetAoBuffer(string source)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
return _aoBuffer.TryGetValue(source, out var buffer) ? buffer : null;
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
public void SetDiBuffer(string provider, int offset, bool[] data)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
if (_diBuffer.ContainsKey(provider) && _diBuffer[provider].ContainsKey(offset))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2024-01-12 18:11:11 +08:00
|
|
|
for (var i = 0; data != null && i < data.Length && i < _diBuffer[provider][offset].Length; i++)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_diBuffer[provider][offset][i] = data[i];
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
public void SetDoBuffer(string provider, int offset, bool[] data)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
if (_doBuffer.ContainsKey(provider) && _doBuffer[provider].ContainsKey(offset))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2024-01-12 18:11:11 +08:00
|
|
|
for (var i = 0; data != null && i < data.Length && i < _doBuffer[provider][offset].Length; i++)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_doBuffer[provider][offset][i] = data[i];
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
public void SetAiBuffer(string provider, int offset, float[] data, int skipSize = 0)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
if (_aiBuffer.ContainsKey(provider) && _aiBuffer[provider].ContainsKey(offset))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2024-01-12 18:11:11 +08:00
|
|
|
for (var i = 0; data != null && i < data.Length && i < _aiBuffer[provider][offset].Length; i++)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_aiBuffer[provider][offset][i + skipSize] = data[i];
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
public void SetAoBuffer(string provider, int offset, float[] data, int bufferStartIndex = 0)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
if (_aoBuffer.ContainsKey(provider) && _aoBuffer[provider].ContainsKey(offset))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2024-01-12 18:11:11 +08:00
|
|
|
for (var i = 0; data != null && i < data.Length && i < _aoBuffer[provider][offset].Length; i++)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_aoBuffer[provider][offset][i] = data[i];
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetBufferBlock(string provider, List<IoBlockItem> lstBlocks)
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
foreach (var lstBlock in lstBlocks)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
|
|
|
switch (lstBlock.Type)
|
|
|
|
{
|
|
|
|
case IoType.AI:
|
2023-12-18 16:39:16 +08:00
|
|
|
if (!_aiBuffer.ContainsKey(provider))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_aiBuffer[provider] = new IoDataCachePerOffset<float[]>(provider);
|
|
|
|
_aiBufferType[provider] = new IoDataCachePerOffset<Type>(provider);
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
if (!_aiBuffer[provider].ContainsKey(lstBlock.Offset))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_aiBuffer[provider][lstBlock.Offset] = new float[lstBlock.Size];
|
2023-04-13 11:51:03 +08:00
|
|
|
_aiBufferType[provider][lstBlock.Offset] = lstBlock.AIOType;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IoType.AO:
|
2023-12-18 16:39:16 +08:00
|
|
|
if (!_aoBuffer.ContainsKey(provider))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_aoBuffer[provider] = new IoDataCachePerOffset<float[]>(provider);
|
|
|
|
_aoBufferType[provider] = new IoDataCachePerOffset<Type>(provider);
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
if (!_aoBuffer[provider].ContainsKey(lstBlock.Offset))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_aoBuffer[provider][lstBlock.Offset] = new float[lstBlock.Size];
|
2023-04-13 11:51:03 +08:00
|
|
|
_aoBufferType[provider][lstBlock.Offset] = lstBlock.AIOType;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IoType.DI:
|
|
|
|
if (!_diBuffer.ContainsKey(provider))
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_diBuffer[provider] = new IoDataCachePerOffset<bool[]>(provider);
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
|
|
|
if (!_diBuffer[provider].ContainsKey(lstBlock.Offset))
|
|
|
|
{
|
|
|
|
_diBuffer[provider][lstBlock.Offset] = new bool[lstBlock.Size];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IoType.DO:
|
|
|
|
if (!_doBuffer.ContainsKey(provider))
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_doBuffer[provider] = new IoDataCachePerOffset<bool[]>(provider);
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
|
|
|
if (!_doBuffer[provider].ContainsKey(lstBlock.Offset))
|
|
|
|
{
|
|
|
|
_doBuffer[provider][lstBlock.Offset] = new bool[lstBlock.Size];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private List<NotifiableIoItem> SubscribeDiData()
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
var list = new List<NotifiableIoItem>();
|
|
|
|
foreach (var item2 in _diMap)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
var item = new NotifiableIoItem
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
|
|
|
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<NotifiableIoItem> SubscribeDoData()
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
var list = new List<NotifiableIoItem>();
|
|
|
|
foreach (var item2 in _doMap)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
var item = new NotifiableIoItem
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
|
|
|
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<NotifiableIoItem> SubscribeAiData()
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
var list = new List<NotifiableIoItem>();
|
|
|
|
foreach (var item2 in _aiMap)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
var item = new NotifiableIoItem
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
|
|
|
Address = item2.Value.Addr,
|
|
|
|
Name = item2.Value.Name,
|
|
|
|
Description = item2.Value.Description,
|
|
|
|
Index = item2.Value.Index,
|
2023-12-18 16:39:16 +08:00
|
|
|
ShortValue = (short)item2.Value.Value,
|
|
|
|
FloatValue = item2.Value.Value,
|
2023-04-13 11:51:03 +08:00
|
|
|
Provider = item2.Value.Provider,
|
|
|
|
BlockOffset = item2.Value.BlockOffset,
|
|
|
|
BlockIndex = item2.Value.Index,
|
|
|
|
Visible = item2.Value.Visible
|
|
|
|
};
|
|
|
|
list.Add(item);
|
|
|
|
}
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
private List<NotifiableIoItem> SubscribeAoData()
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
var list = new List<NotifiableIoItem>();
|
|
|
|
foreach (var item2 in _aoMap)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
var item = new NotifiableIoItem
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
|
|
|
Address = item2.Value.Addr,
|
|
|
|
Name = item2.Value.Name,
|
|
|
|
Description = item2.Value.Description,
|
|
|
|
Index = item2.Value.Index,
|
2023-12-18 16:39:16 +08:00
|
|
|
ShortValue = (short)item2.Value.Value,
|
|
|
|
FloatValue = item2.Value.Value,
|
2023-04-13 11:51:03 +08:00
|
|
|
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<DIAccessor> ioList)
|
|
|
|
{
|
|
|
|
SubscribeIoItemList(provider);
|
2023-12-18 16:39:16 +08:00
|
|
|
var flag = SC.GetConfigItem("System.IsIgnoreSaveDB")?.BoolValue ?? false;
|
|
|
|
foreach (var accessor in ioList)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
|
|
|
accessor.Provider = provider;
|
|
|
|
accessor.BlockOffset = blockOffset;
|
|
|
|
_diMap[accessor.Name] = accessor;
|
2023-12-18 16:39:16 +08:00
|
|
|
if (!_diListPerPlc.ContainsKey(provider))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_diListPerPlc[provider] = new List<DIAccessor>();
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
_diListPerPlc[provider].Add(accessor);
|
2023-04-13 11:51:03 +08:00
|
|
|
_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<DOAccessor> ioList)
|
|
|
|
{
|
|
|
|
SubscribeIoItemList(provider);
|
2023-12-18 16:39:16 +08:00
|
|
|
var flag = SC.GetConfigItem("System.IsIgnoreSaveDB")?.BoolValue ?? false;
|
|
|
|
foreach (var accessor in ioList)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
|
|
|
accessor.Provider = provider;
|
|
|
|
accessor.BlockOffset = blockOffset;
|
|
|
|
_doMap[accessor.Name] = accessor;
|
2023-12-18 16:39:16 +08:00
|
|
|
if (!_doListPerPlc.ContainsKey(provider))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_doListPerPlc[provider] = new List<DOAccessor>();
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
_doListPerPlc[provider].Add(accessor);
|
2023-04-13 11:51:03 +08:00
|
|
|
_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<AIAccessor> ioList)
|
|
|
|
{
|
|
|
|
SubscribeIoItemList(provider);
|
2023-12-18 16:39:16 +08:00
|
|
|
var flag = SC.GetConfigItem("System.IsIgnoreSaveDB")?.BoolValue ?? false;
|
|
|
|
foreach (var accessor in ioList)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
|
|
|
accessor.Provider = provider;
|
|
|
|
accessor.BlockOffset = blockOffset;
|
|
|
|
_aiMap[accessor.Name] = accessor;
|
2023-12-18 16:39:16 +08:00
|
|
|
if (!_aiListPerPlc.ContainsKey(provider))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_aiListPerPlc[provider] = new List<AIAccessor>();
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
_aiListPerPlc[provider].Add(accessor);
|
2023-04-13 11:51:03 +08:00
|
|
|
_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<AOAccessor> ioList)
|
|
|
|
{
|
|
|
|
SubscribeIoItemList(provider);
|
2023-12-18 16:39:16 +08:00
|
|
|
var flag = SC.GetConfigItem("System.IsIgnoreSaveDB")?.BoolValue ?? false;
|
|
|
|
foreach (var accessor in ioList)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
|
|
|
accessor.Provider = provider;
|
|
|
|
accessor.BlockOffset = blockOffset;
|
|
|
|
_aoMap[accessor.Name] = accessor;
|
2023-12-18 16:39:16 +08:00
|
|
|
if (!_aoListPerPlc.ContainsKey(provider))
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_aoListPerPlc[provider] = new List<AOAccessor>();
|
2023-04-13 11:51:03 +08:00
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
_aoListPerPlc[provider].Add(accessor);
|
2023-04-13 11:51:03 +08:00
|
|
|
_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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
private void LoadIoDefinition<T>(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;
|
|
|
|
}
|
|
|
|
|
2024-01-11 15:19:20 +08:00
|
|
|
var disableImmediateCache = false;
|
|
|
|
if (ioNode.HasAttribute("DisImmCache"))
|
|
|
|
{
|
|
|
|
if (!bool.TryParse(ioNode.GetAttribute("DisImmCache"), out disableImmediateCache))
|
|
|
|
disableImmediateCache = false;
|
|
|
|
}
|
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
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;
|
2024-01-11 15:19:20 +08:00
|
|
|
var accessor = (IIOAccessor)Activator.CreateInstance(typeof(T), ioNameWithModule, ioBuffOffset,
|
|
|
|
ioAddrText, IsSimulator, disableImmediateCache);
|
2023-12-18 16:39:16 +08:00
|
|
|
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<T>();
|
|
|
|
|
|
|
|
((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<DIAccessor>(_diBuffer[provider], blockOffset, xmlNodeDiDefs, _diMap, _diListPerPlc,
|
|
|
|
module);
|
|
|
|
|
|
|
|
var xmlNodeDoDefs = xmlDocument.SelectNodes("IO_DEFINE/Dig_Out/DO_ITEM");
|
|
|
|
LoadIoDefinition<DOAccessor>(_doBuffer[provider], blockOffset, xmlNodeDoDefs, _doMap, _doListPerPlc,
|
|
|
|
module);
|
|
|
|
|
|
|
|
var xmlNodeAoDefs = xmlDocument.SelectNodes("IO_DEFINE/Ana_Out/AO_ITEM");
|
|
|
|
LoadIoDefinition<AOAccessor>(_aoBuffer[provider], blockOffset, xmlNodeAoDefs, _aoMap, _aoListPerPlc,
|
|
|
|
module);
|
|
|
|
|
|
|
|
var xmlNodeAiDefs = xmlDocument.SelectNodes("IO_DEFINE/Ana_In/AI_ITEM");
|
|
|
|
LoadIoDefinition<AIAccessor>(_aiBuffer[provider], blockOffset, xmlNodeAiDefs, _aiMap, _aiListPerPlc,
|
|
|
|
module);
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
2023-12-18 16:39:16 +08:00
|
|
|
public void SetIoMap(string provider, Dictionary<int, string> ioMappingPathFile)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
foreach (var item in ioMappingPathFile)
|
2023-04-13 11:51:03 +08:00
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
var diKey = provider + ".DIItemList";
|
2023-04-13 11:51:03 +08:00
|
|
|
if (!_ioItemList.ContainsKey(diKey))
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_ioItemList[diKey] = [];
|
2023-04-13 11:51:03 +08:00
|
|
|
DATA.Subscribe(diKey, () => _ioItemList[diKey]);
|
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
var doKey = provider + ".DOItemList";
|
2023-04-13 11:51:03 +08:00
|
|
|
if (!_ioItemList.ContainsKey(doKey))
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_ioItemList[doKey] = [];
|
2023-04-13 11:51:03 +08:00
|
|
|
DATA.Subscribe(doKey, () => _ioItemList[doKey]);
|
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
var aiKey = provider + ".AIItemList";
|
2023-04-13 11:51:03 +08:00
|
|
|
if (!_ioItemList.ContainsKey(aiKey))
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_ioItemList[aiKey] = [];
|
2023-04-13 11:51:03 +08:00
|
|
|
DATA.Subscribe(aiKey, () => _ioItemList[aiKey]);
|
|
|
|
}
|
2023-12-18 16:39:16 +08:00
|
|
|
var aoKey = provider + ".AOItemList";
|
2023-04-13 11:51:03 +08:00
|
|
|
if (!_ioItemList.ContainsKey(aoKey))
|
|
|
|
{
|
2023-12-18 16:39:16 +08:00
|
|
|
_ioItemList[aoKey] = [];
|
2023-04-13 11:51:03 +08:00
|
|
|
DATA.Subscribe(aoKey, () => _ioItemList[aoKey]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|