Sic.Framework-Nanjing-Baishi/MECF.Framework.Common/MECF/Framework/RT/Core/IoProviders/IoProviderManager.cs

297 lines
8.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}
}
}