123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- using Aitex.Core.RT.IOCore;
- using Aitex.Core.RT.Log;
- using Aitex.Core.RT.SCCore;
- using MECF.Framework.Common.Equipment;
- using MECF.Framework.Common.SCCore;
- using MECF.Framework.Common.Twincat;
- using MECF.Framework.RT.Core.IoProviders;
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Reflection;
- using System.Threading;
- using System.Xml;
- namespace Venus_RT.Devices
- {
- public static class TwinCatMananger
- {
- private static Dictionary<ModuleName, TwincatIO> _mod2twio = new Dictionary<ModuleName, TwincatIO>();
- public static void AddTwinCatWithModule(ModuleName mod, TwincatIO twio)
- {
- Debug.Assert(!_mod2twio.ContainsKey(mod));
- _mod2twio.Add(mod, twio);
- }
- public static TwincatIO GetTwinCatByModuleName(ModuleName mod)
- {
- Debug.Assert(_mod2twio.ContainsKey(mod));
- return _mod2twio[mod];
- }
- }
- public class TwincatIO : IoProvider
- {
- #region 内部变量
- private string _prefix = "MAIN";
- private string _structName = "PcComm";
- /// <summary>
- /// 写入队列
- /// </summary>
- private ConcurrentQueue<(string name, object value)> _writeQueue = new ConcurrentQueue<(string, object)>();
- /// <summary>
- /// 写入线程
- /// </summary>
- private Thread _writeThread = null;
- /// <summary>
- /// 是否正在运行
- /// </summary>
- private bool _isRunning = false;
- /// <summary>
- /// Ado通信对象
- /// </summary>
- private TwincatAdoManager _adoManager = null;
- #endregion
- /// <summary>
- /// 初始化
- /// </summary>
- /// <param name="module"></param>
- /// <param name="name"></param>
- /// <param name="lstBuffers"></param>
- /// <param name="buffer"></param>
- /// <param name="nodeParameter"></param>
- /// <param name="ioMappingPathFile"></param>
- /// <param name="ioModule"></param>
- public override void Initialize(string module, string name, List<IoBlockItem> lstBuffers, IIoBuffer buffer, XmlElement nodeParameter, string ioMappingPathFile, string ioModule)
- {
- Module = module;
- Name = name;
- _adoManager = new TwincatAdoManager();
- TwincatAdoObjectManager.Instance.InitializeModuleAdoManager(module, _adoManager);
- if (SC.ContainsItem("System.TwincatPrefix"))
- {
- _prefix = SC.GetStringValue("System.TwincatPrefix");
- }
- _source = module + "." + name;
- _buffer = buffer;
- _nodeParameter = nodeParameter;
- _blockSections = lstBuffers;
- SetIoMap(_source, 0, ioMappingPathFile, ioModule);
- string configMapPath = ioMappingPathFile.Substring(0, ioMappingPathFile.LastIndexOf('\\'))+"\\TwincatConfig.xml";
- //if (configMapPath != null)
- //{
- // TwincatConfigManager.Instance.SetConfigMap(configMapPath, ioModule);
- //}
- SetRecipe(_source,ioModule);
- SetParameter(nodeParameter);
- State = IoProviderStateEnum.Uninitialized;
- _writeThread = new Thread(new ThreadStart(WriteThreadCallBack));
- _writeThread.IsBackground = true;
- _isRunning = true;
- _writeThread.Start();
- TwinCatMananger.AddTwinCatWithModule(ModuleHelper.Converter(module), this);
- }
- protected override void SetParameter(XmlElement nodeParameter)
- {
- string strIp = nodeParameter.GetAttribute("ip");
- string strPort = nodeParameter.GetAttribute("port");
- int port = int.Parse(strPort);
- string ip = strIp;
- _adoManager.Initialize(ip, port);
- _adoManager.Start();
- }
- private void SetIoMap(string provider, int blockOffset, string xmlPathFile, string module = "")
- {
- XmlDocument xml = new XmlDocument();
- xml.Load(xmlPathFile);
- XmlNodeList lstDi = xml.SelectNodes("IO_DEFINE/Dig_In/DI_ITEM");
- XmlNodeList lstDo = xml.SelectNodes("IO_DEFINE/Dig_Out/DO_ITEM");
- XmlNodeList lstAo = xml.SelectNodes("IO_DEFINE/Ana_Out/AO_ITEM");
- XmlNodeList lstAi = xml.SelectNodes("IO_DEFINE/Ana_In/AI_ITEM");
- _buffer.SetBufferBlock(provider, lstDo.Count, lstDi.Count, lstAi.Count, lstAo.Count);
- var scConfig = SC.GetConfigItem("System.IsIgnoreSaveDB");
- var isIgnoreSaveDB = scConfig == null ? false : scConfig.BoolValue;
- var dibuffer = _buffer.GetDiBuffer(provider);
- List<DIAccessor> diList = new List<DIAccessor>();
- foreach (var diItem in lstDi)
- {
- XmlElement element = diItem as XmlElement;
- if (element == null)
- continue;
- string index = element.GetAttribute("Index");
- string name = element.GetAttribute("Name");
- string address = element.GetAttribute("Addr");
- string description = element.GetAttribute("Description");
- if (string.IsNullOrEmpty(name))
- continue;
- name = name.Trim();
- index = index.Trim();
- string moduleName = string.IsNullOrEmpty(module) ? name : $"{module}.{name}";
- int intIndex;
- if (!int.TryParse(index, out intIndex))
- continue;
- if (!dibuffer.ContainsKey(blockOffset))
- {
- throw new Exception("Not defined DI buffer from IO provider, " + provider);
- }
- DIAccessor diAccessor = new DIAccessor(moduleName, intIndex, dibuffer[blockOffset], dibuffer[blockOffset]);
- diAccessor.IoTableIndex = intIndex;
- diAccessor.Addr = address;
- diAccessor.Provider = provider;
- diAccessor.BlockOffset = blockOffset;
- diAccessor.Description = description;
- diList.Add(diAccessor);
- _adoManager.Subscribe(GetTwincatVariableName(module, name), 1, UpdateInputVariable);
- }
- _buffer.SetIoMap(provider, blockOffset, diList);
- var dobuffer = _buffer.GetDoBuffer(provider);
- List<DOAccessor> doList = new List<DOAccessor>();
- foreach (var doItem in lstDo)
- {
- XmlElement element = doItem as XmlElement;
- if (element == null)
- continue;
- string index = element.GetAttribute("Index");
- string name = element.GetAttribute("Name");
- string address = element.GetAttribute("Addr");
- string description = element.GetAttribute("Description");
- if (string.IsNullOrEmpty(name))
- continue;
- name = name.Trim();
- index = index.Trim();
- //main.pma.av_102
- string moduleName = string.IsNullOrEmpty(module) ? name : $"{module}.{name}";
- int intIndex;
- if (!int.TryParse(index, out intIndex))
- continue;
- if (!dobuffer.ContainsKey(blockOffset))
- {
- throw new Exception("Not defined DO buffer from IO provider, " + provider);
- }
- DOAccessor doAccessor = new DOAccessor(moduleName, intIndex, dobuffer[blockOffset]);
- doAccessor.IoTableIndex = intIndex;
- doAccessor.Addr = address;
- doAccessor.Provider = provider;
- doAccessor.BlockOffset = blockOffset;
- doAccessor.Description = description;
- doList.Add(doAccessor);
- _adoManager.Subscribe(GetTwincatVariableName(module, name), 1, UpdateInputVariable);
- _adoManager.SubscribeOutput(GetTwincatVariableName(module, name));
- }
- _buffer.SetIoMap(provider, blockOffset, doList);
- var aobuffer = _buffer.GetAoBuffer(provider);
- List<AOAccessor> aoList = new List<AOAccessor>();
- foreach (var aoItem in lstAo)
- {
- XmlElement element = aoItem as XmlElement;
- if (element == null)
- continue;
- string index = element.GetAttribute("Index");
- string name = element.GetAttribute("Name");
- string address = element.GetAttribute("Addr");
- string description = element.GetAttribute("Description");
- if (string.IsNullOrEmpty(name))
- continue;
- name = name.Trim();
- index = index.Trim();
- string moduleName = string.IsNullOrEmpty(module) ? name : $"{module}.{name}";
- int intIndex;
- if (!int.TryParse(index, out intIndex))
- continue;
- if (!aobuffer.ContainsKey(blockOffset))
- {
- throw new Exception("Not defined AO buffer from IO provider, " + provider);
- }
- AOAccessor aoAccessor = new AOAccessor(moduleName, intIndex * 2, aobuffer[blockOffset]);
- aoAccessor.IoTableIndex = intIndex;
- aoAccessor.Addr = address;
- aoAccessor.Provider = provider;
- aoAccessor.BlockOffset = blockOffset;
- aoAccessor.Description = description;
- aoList.Add(aoAccessor);
- _adoManager.Subscribe(GetTwincatVariableName(module, name), 4, UpdateInputVariable);//float在Twincat中32位,数据长度为4
- _adoManager.SubscribeOutput(GetTwincatVariableName(module, name));
- }
- _buffer.SetIoMap(provider, blockOffset, aoList);
- var aibuffer = _buffer.GetAiBuffer(provider);
- List<AIAccessor> aiList = new List<AIAccessor>();
- foreach (var aiItem in lstAi)
- {
- XmlElement element = aiItem as XmlElement;
- if (element == null)
- continue;
- string index = element.GetAttribute("Index");
- string name = element.GetAttribute("Name");
- string address = element.GetAttribute("Addr");
- string description = element.GetAttribute("Description");
- if (string.IsNullOrEmpty(name))
- continue;
- name = name.Trim();
- index = index.Trim();
- string moduleName = string.IsNullOrEmpty(module) ? name : $"{module}.{name}";
- int intIndex;
- if (!int.TryParse(index, out intIndex))
- continue;
- if (!aibuffer.ContainsKey(blockOffset))
- {
- throw new Exception("Not defined AI buffer from IO provider, " + provider);
- }
- AIAccessor aiAccessor = new AIAccessor(moduleName, intIndex * 2, aibuffer[blockOffset]);
- aiAccessor.IoTableIndex = intIndex;
- aiAccessor.Addr = address;
- aiAccessor.Provider = provider;
- aiAccessor.BlockOffset = blockOffset;
- aiAccessor.Description = description;
- aiList.Add(aiAccessor);
- _adoManager.Subscribe(GetTwincatVariableName(module, name), 4, UpdateInputVariable);//float在Twincat中32位,数据长度为4
- }
- _buffer.SetIoMap(provider, blockOffset, aiList);
- }
-
- /// <summary>
- /// 获取Twincat变量名称
- /// </summary>
- /// <param name="name"></param>
- /// <returns></returns>
- private string GetTwincatVariableName(string module, string name)
- {
- if (!string.IsNullOrEmpty(_prefix))
- {
- return $"{_prefix}.{_structName}.{name}";
- }
- else
- {
- return name;
- }
- }
- /// <summary>
- /// 输入变量数值发生变化
- /// </summary>
- /// <param name="variableName"></param>
- /// <param name="value"></param>
- private void UpdateInputVariable(string variableName, object value)
- {
- if (!string.IsNullOrEmpty(_prefix))
- {
- _buffer.SetBufferValue(_source, $"{variableName.Replace($"{_prefix}.", "")}", value);
- }
- else
- {
- _buffer.SetBufferValue(_source, $"{Module}.{variableName}", value);
- }
- }
- protected override void Close()
- {
- _isRunning = false;
- while (_writeQueue.Count != 0)
- {
- try
- {
- _writeQueue.TryDequeue(out var data);
- }
- catch
- {
- }
- }
- if (_writeThread != null)
- {
- try
- {
- _writeThread.Abort();
- }
- catch
- {
- }
- _writeThread = null;
- }
- }
- public override void Open()
- {
- }
- protected override short[] ReadAi(int offset, int size)
- {
- return null;
- }
- protected override bool[] ReadDi(int offset, int size)
- {
- return null;
- }
- protected override void WriteAo(int offset, short[] buffer)
- {
- }
- protected override void WriteDo(int offset, bool[] buffer)
- {
- }
- public override void SetValue(string variableName, object value)
- {
- if (_isRunning)
- {
- var data = (variableName, value);
- _writeQueue.Enqueue(data);
- }
- else
- {
- LOG.Write(eEvent.ERR_TWINCAT, Module, $"{Module}.{Name} stopped");
- }
- }
- /// <summary>
- /// 写入线程
- /// </summary>
- private void WriteThreadCallBack()
- {
- while (_isRunning)
- {
- if (_writeQueue.Count == 0)
- {
- Thread.Sleep(5);
- continue;
- }
- if (_writeQueue.TryDequeue(out var data))
- {
- string variableName = data.name.Replace($"{Module}.", "");
- string twincatName = GetTwincatVariableName(Module, variableName);
- var result = _adoManager.WriteValue(twincatName, data.value);
- if (!result.success && result.status == 1)//写入异常
- {
- _writeQueue.Enqueue(data);
- }
- }
- Thread.Sleep(1);
- }
- }
- public class TwincatFeedbackBuffer{
- //缓存process过程变量
- private readonly Dictionary<string, object> _feedbackSignal = new Dictionary<string, object>();
- // 添加信号到缓存中
- public void AddSignal(string name, object value)
- {
- _feedbackSignal[name] = value;
- }
- // 获取信号值,返回一个类型为 object 的值
- public object GetSignal(string name)
- {
- if (_feedbackSignal.TryGetValue(name, out var value))
- {
- return value;
- }
- else
- {
- throw new KeyNotFoundException($"Signal with name '{name}' not found.");
- }
- }
- }
- private void UpdateRecipeFeedBackVariable(string variableName, object value)
- {
- //byte[] bytes = (byte[])value;
- //int byteNumber = 0;
- //ProcessRecipeFeedBack processRecipeFeedBack = TwincatFeedBackManager.Instance.GetModuleFeebback(Module);
- //Type _feedBackItemType = processRecipeFeedBack.GetType();
- //var _feedBackItems = _feedBackItemType.GetFields(BindingFlags.Public | BindingFlags.Instance);
- //foreach (var _feedBackItem in _feedBackItems)
- //{
- // _feedBackItem.SetValue(processRecipeFeedBack, GetPropertyValue(_feedBackItem, bytes, ref byteNumber));
- //}
- }
- private object GetPropertyValue(FieldInfo propertyInfo,byte[] bytes,ref int bytesNumber)
- {
- switch(propertyInfo.FieldType.Name.ToLower())
- {
- case "boolean":
- return bytes[bytesNumber++] == 1 ? true : false;
- case "int16":
- short shortValue= BitConverter.ToInt16(bytes, bytesNumber);
- bytesNumber += 2;
- return shortValue;
- case "int32":
- int intValue= BitConverter.ToInt32(bytes, bytesNumber);
- bytesNumber += 4;
- return intValue;
- case "float":
- float floatValue=BitConverter.ToSingle(bytes, bytesNumber);
- bytesNumber += 4;
- return floatValue;
- case "double":
- double doubleValue = BitConverter.ToDouble(bytes, bytesNumber);
- bytesNumber += 8;
- return doubleValue;
- default:
- return null;
- }
- }
- private void SetRecipe(string source,string module = "")
- {
- //TwincatFeedBackManager.Instance.Initialize(module);
- //Array recipeTypes = Enum.GetValues(typeof(KeplerRecipeType));
- //var _processRecipeFeedBack = TwincatFeedBackManager.Instance.GetModuleFeebback(module);
- //int length = Marshal.SizeOf(_processRecipeFeedBack);
- //string twincatFeedBackItemName = GetTwincatVariableName(module, "processFeedBack");
- //_adoManager.Subscribe(twincatFeedBackItemName, length, UpdateRecipeFeedBackVariable);
- //foreach (var type in recipeTypes)
- //{
- // string twincatName = GetTwincatVariableName(module, type.ToString());
- // _adoManager.SubscribeOutput(twincatName);
- //}
- }
- private int GetDataTypeLength(string type)
- {
- switch(type.ToLower())
- {
- case "boolean":
- return 1;
- case "int16":
- return 2;
- default:
- return 0;
- }
- }
- //写入recipe
- //public override bool WriteRecipe<T>(ModuleName moduleName,RecipeType currentRecipeType,T data)
- //{
- // string twincatName = GetTwincatVariableName(Module, currentRecipeType.ToString());
- // var result = _adoManager.WriteStruct(twincatName, data);
- // return result.success;
- //}
- }
- }
|