498 lines
13 KiB
C#
498 lines
13 KiB
C#
#define DEBUG
|
||
using System;
|
||
using System.Collections.Concurrent;
|
||
using System.Collections.Generic;
|
||
using System.Diagnostics;
|
||
using System.Drawing;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Text.RegularExpressions;
|
||
using System.Threading.Tasks;
|
||
using System.Xml;
|
||
using Aitex.Core.RT.DataCenter;
|
||
using Aitex.Core.RT.Log;
|
||
using Aitex.Core.Util;
|
||
using MECF.Framework.Common.Equipment;
|
||
|
||
namespace Aitex.Core.RT.Device
|
||
{
|
||
public class DeviceManagerBase : IDeviceManager
|
||
{
|
||
|
||
#region Variables
|
||
|
||
|
||
private readonly Dictionary<string, IDevice> _nameDevice = new();
|
||
private readonly Dictionary<Type, List<IDevice>> _typeDevice = new();
|
||
private readonly DeviceTimer _timer = new();
|
||
private readonly R_TRIG _trigExceed500 = new();
|
||
private readonly ConcurrentBag<IDevice> _optionDevice = new();
|
||
private readonly object _lockerDevice = new();
|
||
|
||
#endregion
|
||
|
||
#region MyRegion
|
||
|
||
public DeviceManagerBase()
|
||
{
|
||
DEVICE.Manager = this;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Properties
|
||
|
||
/// <summary>
|
||
/// 返回当前设备管理器映射的XML配置文件节点。
|
||
/// </summary>
|
||
protected XmlElement DeviceModelNodes { get; private set; }
|
||
|
||
/// <summary>
|
||
/// 设置或返回是否以异步方式初始化当前管理器中的设备。
|
||
/// </summary>
|
||
public bool DisableAsyncInitialize { get; set; }
|
||
|
||
#endregion
|
||
|
||
|
||
#region Methods
|
||
|
||
private void InitDevice(IDevice device)
|
||
{
|
||
try
|
||
{
|
||
if (!device.Initialize())
|
||
{
|
||
LOG.Write(device.Name + " initialize failed.");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 向设备管理器的设备字典中添加一个设备实例。
|
||
/// </summary>
|
||
/// <param name="device"></param>
|
||
protected virtual void QueueDevice(IDevice device)
|
||
{
|
||
QueueDevice(device.Name, device);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 向设备管理器的设备字典中添加一个设备实例,并自定义该设备在字典中的Key。
|
||
/// </summary>
|
||
/// <param name="key"></param>
|
||
/// <param name="device"></param>
|
||
protected void QueueDevice(string key, IDevice device)
|
||
{
|
||
lock (_lockerDevice)
|
||
{
|
||
Debug.Assert(!_nameDevice.ContainsKey(key), "DeviceModel config file contains duplicated name " + key);
|
||
_nameDevice.Add(key, device);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 终止当前对象。
|
||
/// </summary>
|
||
public virtual void Terminate()
|
||
{
|
||
lock (_lockerDevice)
|
||
{
|
||
foreach (var value in _nameDevice.Values)
|
||
{
|
||
value.Terminate();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 后台扫面线程调用的方法。
|
||
/// </summary>
|
||
public void Monitor()
|
||
{
|
||
lock (_lockerDevice)
|
||
{
|
||
foreach (var value in _nameDevice.Values)
|
||
{
|
||
try
|
||
{
|
||
_timer.Start(0.0);
|
||
value.Monitor();
|
||
_trigExceed500.CLK = _timer.GetElapseTime() > 500.0;
|
||
if (_trigExceed500.Q)
|
||
{
|
||
LOG.Warning($"{value.Module}.{value.Name} monitor time {_timer.GetElapseTime()} ms");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex, $"Monitor {value.Name} Exception");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public void Reset()
|
||
{
|
||
lock (_lockerDevice)
|
||
{
|
||
foreach (var value in _nameDevice.Values)
|
||
{
|
||
value.Reset();
|
||
}
|
||
_trigExceed500.RST = true;
|
||
}
|
||
}
|
||
|
||
public void Initialize(string modelFile, string type, ModuleName mod = ModuleName.System, string ioModule = "", bool endCallInit = true)
|
||
{
|
||
if (!File.Exists(modelFile))
|
||
{
|
||
throw new ApplicationException($"did not find the device model file {modelFile} ");
|
||
}
|
||
var xmlDocument = new XmlDocument();
|
||
try
|
||
{
|
||
xmlDocument.Load(modelFile);
|
||
if (!(xmlDocument.SelectSingleNode("DeviceModelDefine") is XmlElement xmlElement))
|
||
{
|
||
throw new ApplicationException($"device mode file {modelFile} is not valid");
|
||
}
|
||
var attribute = xmlElement.GetAttribute("type");
|
||
if (attribute != type)
|
||
{
|
||
throw new ApplicationException($"the type {attribute} in device mode file {modelFile} is inaccordance with the system type {type}");
|
||
}
|
||
DeviceModelNodes = xmlElement;
|
||
foreach (XmlNode childNode in xmlElement.ChildNodes)
|
||
{
|
||
if (childNode.NodeType == XmlNodeType.Comment || !(childNode is XmlElement xmlElement2))
|
||
{
|
||
continue;
|
||
}
|
||
var text = xmlElement2.GetAttribute("assembly");
|
||
if (string.IsNullOrEmpty(text))
|
||
{
|
||
text = "MECF.Framework.RT.EquipmentLibrary";
|
||
}
|
||
var text2 = xmlElement2.Name.Substring(0, xmlElement2.Name.Length - 1);
|
||
var text3 = xmlElement2.GetAttribute("classType");
|
||
if (string.IsNullOrEmpty(text3))
|
||
{
|
||
text3 = "Aitex.Core.RT.Device.Unit." + text2;
|
||
}
|
||
var assembly = Assembly.Load(text);
|
||
var type2 = assembly.GetType(text3);
|
||
if (type2 == null)
|
||
{
|
||
continue;
|
||
}
|
||
foreach (var childNode2 in xmlElement2.ChildNodes)
|
||
{
|
||
if (!(childNode2 is XmlElement xmlElement3))
|
||
{
|
||
LOG.Write("Device Model File contains non element node, " + (childNode2 as XmlNode).Value);
|
||
continue;
|
||
}
|
||
var device = Activator.CreateInstance(type2, mod.ToString(), xmlElement3, ioModule) as IDevice;
|
||
if (xmlElement3.HasAttribute("option") && Convert.ToBoolean(xmlElement3.Attributes["option"].Value))
|
||
{
|
||
_optionDevice.Add(device);
|
||
continue;
|
||
}
|
||
QueueDevice(device);
|
||
DATA.Subscribe(device, $"{device.Module}.{text2}.{device.Name}");
|
||
if (!_typeDevice.ContainsKey(type2))
|
||
{
|
||
_typeDevice[type2] = new List<IDevice>();
|
||
}
|
||
_typeDevice[type2].Add(device);
|
||
if (DisableAsyncInitialize)
|
||
{
|
||
InitDevice(device);
|
||
continue;
|
||
}
|
||
var task = Task.Run(delegate
|
||
{
|
||
InitDevice(device);
|
||
});
|
||
}
|
||
}
|
||
if (endCallInit)
|
||
{
|
||
Initialize();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
}
|
||
}
|
||
|
||
public void Initialize(string modelFile, string modelType, string moduleName, string ioPath, string scPath)
|
||
{
|
||
if (!File.Exists(modelFile))
|
||
{
|
||
throw new ApplicationException($"did not find the device model file {modelFile} ");
|
||
}
|
||
var xmlDocument = new XmlDocument();
|
||
try
|
||
{
|
||
xmlDocument.Load(modelFile);
|
||
if (!(xmlDocument.SelectSingleNode("DeviceModelDefine") is XmlElement xmlElement))
|
||
{
|
||
throw new ApplicationException($"device mode file {modelFile} is not valid");
|
||
}
|
||
var attribute = xmlElement.GetAttribute("type");
|
||
if (attribute != modelType)
|
||
{
|
||
throw new ApplicationException($"the type {attribute} in device mode file {modelFile} is different with the system type {modelType}");
|
||
}
|
||
DeviceModelNodes = xmlElement;
|
||
foreach (XmlNode childNode in xmlElement.ChildNodes)
|
||
{
|
||
if (childNode.NodeType == XmlNodeType.Comment || !(childNode is XmlElement xmlElement2))
|
||
{
|
||
continue;
|
||
}
|
||
var text = xmlElement2.GetAttribute("assembly");
|
||
if (string.IsNullOrEmpty(text))
|
||
{
|
||
text = "MECF.Framework.RT.EquipmentLibrary";
|
||
}
|
||
var text2 = xmlElement2.Name.Substring(0, xmlElement2.Name.Length - 1);
|
||
var text3 = xmlElement2.GetAttribute("classType");
|
||
if (string.IsNullOrEmpty(text3))
|
||
{
|
||
text3 = "Aitex.Core.RT.Device.Unit." + text2;
|
||
}
|
||
var assembly = Assembly.Load(text);
|
||
var type = assembly.GetType(text3);
|
||
if (type == null)
|
||
{
|
||
continue;
|
||
}
|
||
foreach (var childNode2 in xmlElement2.ChildNodes)
|
||
{
|
||
if (!(childNode2 is XmlElement xmlElement3))
|
||
{
|
||
LOG.Write("Device Model File contains non element node, " + (childNode2 as XmlNode).Value);
|
||
continue;
|
||
}
|
||
xmlElement3.SetAttribute("ioPath", ioPath);
|
||
xmlElement3.SetAttribute("scPath", scPath);
|
||
var device = Activator.CreateInstance(type, moduleName, xmlElement3, ioPath) as IDevice;
|
||
if (xmlElement3.HasAttribute("option") && Convert.ToBoolean(xmlElement3.Attributes["option"]))
|
||
{
|
||
_optionDevice.Add(device);
|
||
continue;
|
||
}
|
||
DATA.Subscribe(device, $"{device.Module}.{text2}.{device.Name}");
|
||
QueueDevice(device);
|
||
if (!_typeDevice.ContainsKey(type))
|
||
{
|
||
_typeDevice[type] = new List<IDevice>();
|
||
}
|
||
_typeDevice[type].Add(device);
|
||
if (DisableAsyncInitialize)
|
||
{
|
||
InitDevice(device);
|
||
continue;
|
||
}
|
||
var task = Task.Run(delegate
|
||
{
|
||
InitDevice(device);
|
||
});
|
||
}
|
||
}
|
||
Initialize();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 向当前设备管理器中添加一个自定义设备。
|
||
/// </summary>
|
||
/// <param name="device">设备对象的实例。</param>
|
||
/// <param name="groupType"></param>
|
||
/// <param name="deviceType">设备对象实例的类型。</param>
|
||
/// <returns></returns>
|
||
public IDevice AddCustomDevice(IDevice device, string groupType, Type deviceType)
|
||
{
|
||
lock (_lockerDevice)
|
||
{
|
||
DATA.Subscribe(device, $"{device.Module}.{groupType}.{device.Name}");
|
||
if (!string.IsNullOrEmpty(device.Module) && device.Module != ModuleName.System.ToString())
|
||
{
|
||
_nameDevice.Add(device.Module + "." + device.Name, device);
|
||
}
|
||
else
|
||
{
|
||
_nameDevice.Add(device.Name, device);
|
||
}
|
||
if (!_typeDevice.ContainsKey(deviceType))
|
||
{
|
||
_typeDevice[deviceType] = new List<IDevice>();
|
||
}
|
||
_typeDevice[deviceType].Add(device);
|
||
device.Initialize();
|
||
}
|
||
return device;
|
||
}
|
||
|
||
public IDevice AddCustomDevice(IDevice device, Type deviceType)
|
||
{
|
||
lock (_lockerDevice)
|
||
{
|
||
try
|
||
{
|
||
DATA.Subscribe(device, $"{device.Module}.{device.Name}");
|
||
_nameDevice.Add(device.Name, device);
|
||
if (!_typeDevice.ContainsKey(deviceType))
|
||
{
|
||
_typeDevice[deviceType] = new List<IDevice>();
|
||
}
|
||
_typeDevice[deviceType].Add(device);
|
||
device.Initialize();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
}
|
||
}
|
||
return device;
|
||
}
|
||
|
||
public IDevice AddCustomDevice(IDevice device)
|
||
{
|
||
lock (_lockerDevice)
|
||
{
|
||
try
|
||
{
|
||
DATA.Subscribe(device, $"{device.Module}.{device.Name}");
|
||
_nameDevice.Add(device.Name, device);
|
||
if (!_typeDevice.ContainsKey(device.GetType()))
|
||
{
|
||
_typeDevice[device.GetType()] = new List<IDevice>();
|
||
}
|
||
_typeDevice[device.GetType()].Add(device);
|
||
device.Initialize();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
}
|
||
}
|
||
return device;
|
||
}
|
||
|
||
public IDevice AddCustomModuleDevice(IDevice device)
|
||
{
|
||
lock (_lockerDevice)
|
||
{
|
||
try
|
||
{
|
||
DATA.Subscribe(device, $"{device.Module}.{device.Name}");
|
||
_nameDevice.Add(device.Module + "." + device.Name, device);
|
||
if (!_typeDevice.ContainsKey(device.GetType()))
|
||
{
|
||
_typeDevice[device.GetType()] = new List<IDevice>();
|
||
}
|
||
_typeDevice[device.GetType()].Add(device);
|
||
device.Initialize();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
}
|
||
}
|
||
return device;
|
||
}
|
||
|
||
public virtual bool Initialize()
|
||
{
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取指定名称和类型的设备的实例。
|
||
/// </summary>
|
||
/// <param name="name">设备名称。</param>
|
||
/// <typeparam name="T">设备类型。</typeparam>
|
||
/// <returns></returns>
|
||
public T GetDevice<T>(string name) where T : class, IDevice
|
||
{
|
||
if (!_nameDevice.ContainsKey(name))
|
||
{
|
||
return null;
|
||
}
|
||
return _nameDevice[name] as T;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取指定名称的设备的实例。
|
||
/// </summary>
|
||
/// <param name="name"></param>
|
||
/// <returns></returns>
|
||
public object GetDevice(string name)
|
||
{
|
||
if (!_nameDevice.ContainsKey(name))
|
||
{
|
||
return null;
|
||
}
|
||
return _nameDevice[name];
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取包含所有指定类型的设备实例的列表。
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <returns></returns>
|
||
public List<T> GetDevice<T>() where T : class, IDevice
|
||
{
|
||
if (!_typeDevice.ContainsKey(typeof(T)))
|
||
{
|
||
return null;
|
||
}
|
||
var list = new List<T>();
|
||
foreach (var item in _typeDevice[typeof(T)])
|
||
{
|
||
list.Add(item as T);
|
||
}
|
||
return list;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前设备管理器中的所有设备的列表。
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public List<IDevice> GetAllDevice()
|
||
{
|
||
return _nameDevice.Values.ToList();
|
||
}
|
||
|
||
public object GetOptionDevice(string name, Type type)
|
||
{
|
||
foreach (var item in _optionDevice)
|
||
{
|
||
if (item.Module + "." + item.Name == name && (type == null || item.GetType() == type))
|
||
{
|
||
return item;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
|
||
#endregion
|
||
}
|
||
}
|