297 lines
8.9 KiB
C#
297 lines
8.9 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Diagnostics;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Threading;
|
||
using System.Xml;
|
||
using Aitex.Core.RT.Event;
|
||
using Aitex.Core.RT.Log;
|
||
using Aitex.Core.RT.SCCore;
|
||
using Aitex.Core.Util;
|
||
using MECF.Framework.Common.Equipment;
|
||
using MECF.Framework.Common.IOCore;
|
||
|
||
namespace MECF.Framework.RT.Core.IoProviders
|
||
{
|
||
public class IoProviderManager : Singleton<IoProviderManager>
|
||
{
|
||
private readonly List<IIoProvider> _providers = new ();
|
||
|
||
private readonly Dictionary<string, IIoProvider> _dicProviders = new ();
|
||
|
||
public List<IIoProvider> Providers => _providers;
|
||
|
||
public IIoProvider GetProvider(string name)
|
||
{
|
||
if (_dicProviders.ContainsKey(name))
|
||
{
|
||
return _dicProviders[name];
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public void Initialize(string xmlConfigFile, Dictionary<string, Dictionary<int, string>> ioMappingPathFile)
|
||
{
|
||
var xmlDocument = new XmlDocument();
|
||
try
|
||
{
|
||
xmlDocument.Load(xmlConfigFile);
|
||
var xmlNodeIoProviders = xmlDocument.SelectNodes("IoProviders/IoProvider");
|
||
foreach (var node in xmlNodeIoProviders)
|
||
{
|
||
if (!(node is XmlElement nodeProvider) || !(nodeProvider.SelectSingleNode("Parameter") is XmlElement nodeParameter))
|
||
{
|
||
continue;
|
||
}
|
||
var attrModule = nodeProvider.GetAttribute("module").Trim();
|
||
var attrName = nodeProvider.GetAttribute("name").Trim();
|
||
var attrClass = nodeProvider.GetAttribute("class").Trim();
|
||
var attrAssembly = nodeProvider.GetAttribute("assembly").Trim();
|
||
var attrLoadCond = nodeProvider.GetAttribute("load_condition").Trim();
|
||
var isSim = SC.GetConfigItem("System.IsSimulatorMode").BoolValue;
|
||
if ((isSim && attrLoadCond != "0" && attrLoadCond != "2") || (!isSim && attrLoadCond != "1" && attrLoadCond != "2"))
|
||
{
|
||
continue;
|
||
}
|
||
var ioProviderName = attrModule + "." + attrName;
|
||
var type = Assembly.Load(attrAssembly).GetType(attrClass);
|
||
if (type == null)
|
||
{
|
||
throw new Exception(string.Format("ioProvider config file class and assembly not valid," + ioProviderName));
|
||
}
|
||
IIoProvider ioProvider;
|
||
try
|
||
{
|
||
ioProvider = (IIoProvider)Activator.CreateInstance(type);
|
||
_providers.Add(ioProvider);
|
||
_dicProviders[ioProviderName] = ioProvider;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
throw new Exception(string.Format("ioProvider can not be created," + ioProviderName));
|
||
}
|
||
var list = new List<IoBlockItem>();
|
||
var xmlNodeBlocks = nodeProvider.SelectNodes("Blocks/Block");
|
||
foreach (var nodeBlock in xmlNodeBlocks)
|
||
{
|
||
if (!(nodeBlock is XmlElement xmlNodeBlock))
|
||
{
|
||
continue;
|
||
}
|
||
var ioBlockItem = new IoBlockItem();
|
||
var attrType = xmlNodeBlock.GetAttribute("type");
|
||
var attrOffset = xmlNodeBlock.GetAttribute("offset");
|
||
var attrSize = xmlNodeBlock.GetAttribute("size");
|
||
var attrValueType = xmlNodeBlock.GetAttribute("value_type");
|
||
if (!int.TryParse(attrOffset, out var result))
|
||
{
|
||
continue;
|
||
}
|
||
ioBlockItem.Offset = result;
|
||
if (int.TryParse(attrSize, out result))
|
||
{
|
||
ioBlockItem.Size = result;
|
||
switch (attrType.ToLower())
|
||
{
|
||
case "ai":
|
||
ioBlockItem.Type = IoType.AI;
|
||
break;
|
||
case "ao":
|
||
ioBlockItem.Type = IoType.AO;
|
||
break;
|
||
case "di":
|
||
ioBlockItem.Type = IoType.DI;
|
||
break;
|
||
case "do":
|
||
ioBlockItem.Type = IoType.DO;
|
||
break;
|
||
default:
|
||
continue;
|
||
}
|
||
if (ioBlockItem.Type == IoType.AI || ioBlockItem.Type == IoType.AO)
|
||
{
|
||
ioBlockItem.AIOType = ((string.IsNullOrEmpty(attrValueType) || attrValueType.ToLower() != "float") ? typeof(short) : typeof(float));
|
||
}
|
||
list.Add(ioBlockItem);
|
||
}
|
||
}
|
||
if (ioMappingPathFile.ContainsKey(ioProviderName))
|
||
{
|
||
ioProvider.Initialize(attrModule, attrName, list, Singleton<IoManager>.Instance, nodeParameter, ioMappingPathFile[ioProviderName]);
|
||
ioProvider.Start();
|
||
continue;
|
||
}
|
||
throw new Exception(string.Format("can not find io map config files," + ioProviderName));
|
||
}
|
||
}
|
||
catch (Exception ex2)
|
||
{
|
||
throw new ApplicationException("IoProvider configuration not valid," + ex2.Message);
|
||
}
|
||
}
|
||
|
||
public void Initialize(string xmlConfigFile)
|
||
{
|
||
var xmlDoc = new XmlDocument();
|
||
try
|
||
{
|
||
xmlDoc.Load(xmlConfigFile);
|
||
var xmlNodeList = xmlDoc.SelectNodes("IoProviders/IoProvider");
|
||
foreach (var item in xmlNodeList)
|
||
{
|
||
if (!(item is XmlElement xmlElement) || !(xmlElement.SelectSingleNode("Parameter") is XmlElement nodeParameter))
|
||
{
|
||
continue;
|
||
}
|
||
var moduleName = xmlElement.GetAttribute("module").Trim();
|
||
var providerName = xmlElement.GetAttribute("name").Trim();
|
||
var typeName = xmlElement.GetAttribute("class").Trim();
|
||
var assemblyString = xmlElement.GetAttribute("assembly").Trim();
|
||
var loadCond = xmlElement.GetAttribute("load_condition").Trim();
|
||
var isSim = SC.GetConfigItem("System.IsSimulatorMode").BoolValue;
|
||
if ((isSim && loadCond != "0" && loadCond != "2") || (!isSim && loadCond != "1" && loadCond != "2"))
|
||
{
|
||
continue;
|
||
}
|
||
var ioProviderName = moduleName + "." + providerName;
|
||
var type = Assembly.Load(assemblyString).GetType(typeName);
|
||
if (type == null)
|
||
{
|
||
throw new Exception(string.Format("ioProvider config file class and assembly not valid," + ioProviderName));
|
||
}
|
||
IIoProvider ioProvider;
|
||
try
|
||
{
|
||
ioProvider = (IIoProvider)Activator.CreateInstance(type);
|
||
_providers.Add(ioProvider);
|
||
_dicProviders[ioProviderName] = ioProvider;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
throw new Exception(string.Format("ioProvider can not be created," + ioProviderName));
|
||
}
|
||
var list = new List<IoBlockItem>();
|
||
var nodeBlocks = xmlElement.SelectNodes("Blocks/Block");
|
||
foreach (var nodeBlock in nodeBlocks)
|
||
{
|
||
if (!(nodeBlock is XmlElement xmlBlock))
|
||
{
|
||
continue;
|
||
}
|
||
var ioBlockItem = new IoBlockItem();
|
||
var attrType = xmlBlock.GetAttribute("type");
|
||
var attrOffset = xmlBlock.GetAttribute("offset");
|
||
var attrSize = xmlBlock.GetAttribute("size");
|
||
var attrValueType = xmlBlock.GetAttribute("value_type");
|
||
if (!int.TryParse(attrOffset, out var result))
|
||
{
|
||
continue;
|
||
}
|
||
ioBlockItem.Offset = result;
|
||
if (int.TryParse(attrSize, out result))
|
||
{
|
||
ioBlockItem.Size = result;
|
||
switch (attrType.ToLower())
|
||
{
|
||
case "ai":
|
||
ioBlockItem.Type = IoType.AI;
|
||
break;
|
||
case "ao":
|
||
ioBlockItem.Type = IoType.AO;
|
||
break;
|
||
case "di":
|
||
ioBlockItem.Type = IoType.DI;
|
||
break;
|
||
case "do":
|
||
ioBlockItem.Type = IoType.DO;
|
||
break;
|
||
default:
|
||
continue;
|
||
}
|
||
if (ioBlockItem.Type == IoType.AI || ioBlockItem.Type == IoType.AO)
|
||
{
|
||
ioBlockItem.AIOType = ((string.IsNullOrEmpty(attrValueType) || attrValueType.ToLower() != "float") ? typeof(short) : typeof(float));
|
||
}
|
||
list.Add(ioBlockItem);
|
||
}
|
||
}
|
||
var ioModule = xmlElement.GetAttribute("map_module").Trim();
|
||
var ioMapFileName = xmlElement.GetAttribute("map_file").Trim();
|
||
var fileInfo = new FileInfo(xmlConfigFile);
|
||
var ioMappingPathFile = fileInfo.Directory.FullName + "\\" + ioMapFileName;
|
||
ioProvider.Initialize(moduleName, providerName, list, Singleton<IoManager>.Instance, nodeParameter, ioMappingPathFile, ioModule);
|
||
ioProvider.Start();
|
||
}
|
||
}
|
||
catch (Exception ex2)
|
||
{
|
||
throw new ApplicationException("IoProvider configuration not valid," + ex2.Message);
|
||
}
|
||
}
|
||
|
||
public void Terminate()
|
||
{
|
||
try
|
||
{
|
||
foreach (var provider in _providers)
|
||
{
|
||
provider.Stop();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
}
|
||
}
|
||
|
||
public void Reset()
|
||
{
|
||
try
|
||
{
|
||
foreach (var provider in _providers)
|
||
{
|
||
provider.Reset();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 等待PLC第一次同步数据,以免缓存数据默认值导致误报警。
|
||
/// </summary>
|
||
/// <param name="timeout"></param>
|
||
public void WaitFirstSync(int timeout = 3000)
|
||
{
|
||
var sw = new Stopwatch();
|
||
sw.Start();
|
||
|
||
LOG.Info($"{nameof(IoProviderManager)} Waiting for the first data synchronization from the PLC.");
|
||
while (true)
|
||
{
|
||
var notSyncedPlc = _providers.Where(x => x.IsSynced == false).ToArray();
|
||
if (notSyncedPlc.Length == 0)
|
||
-break;
|
||
|
||
if (sw.ElapsedMilliseconds > timeout)
|
||
{
|
||
var plcNames = string.Join(", ", notSyncedPlc.Select(x => $"{x.Module}.{x.Name}").ToArray());
|
||
EV.PostWarningLog(ModuleName.System.ToString(),
|
||
$"The PLC(s) [{plcNames}] has not synchronized data in {timeout}ms, " +
|
||
$"which may lead to erroneous warnings or alarms in the system.");
|
||
break;
|
||
}
|
||
|
||
// keep waiting
|
||
Thread.Sleep(10);
|
||
}
|
||
}
|
||
}
|
||
}
|