using Aitex.Core.RT.IOCore; using Aitex.Core.RT.Log; using Aitex.Core.Util; using DocumentFormat.OpenXml.Wordprocessing; using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using TwinCAT.Ads; using Venus_Core; namespace MECF.Framework.Common.Twincat { /// /// 变量数值发生变化委托声明 /// /// /// public delegate void OnUpdateModuleVariableValue(string variableName, object value); /// /// Twicat Ado通信 /// public class TwincatAdoManager { #region 内部变量 /// /// IO长度字典(key-变量名称,value-变量数据长度) /// private ConcurrentDictionary _ioLengthDic = new ConcurrentDictionary(); /// /// 输出变量集合 /// private ConcurrentBag _outputBag = new ConcurrentBag(); /// /// 主动读取变量集合 /// private ConcurrentBag _inputBag = new ConcurrentBag(); /// /// Twincat 对象 /// private TcAdsClient _adsClient = null; /// /// 地址 /// private string _ipAddress = ""; /// /// 端口号 /// private int _port = 851; /// /// 句柄变量名称字典(key-创建句柄,value-变量名称) /// private Dictionary _notificationHandleNameDic = new Dictionary(); /// /// 模块变量更新委托字典(key-模块.变量,value-变量委托事件 /// private Dictionary _moduleVariableActionDic = new Dictionary(); /// /// 写变更名称句柄字典(key-变量名称,value-创建句柄) /// private Dictionary _writeNameHandleDic = new Dictionary(); /// /// 主动读取名称字典(key-变量名称,value-创建句柄) /// private Dictionary _readNameHandleDic = new Dictionary(); private AdsStream _adsStream; private BinaryReader _reader; /// /// 连接状态 /// private bool _isConnected; #endregion /// /// 订阅变量 /// /// /// public void Subscribe(string itemName,int itemLength, OnUpdateModuleVariableValue onUpdateModuleVariableValue) { _ioLengthDic[itemName] = itemLength; _moduleVariableActionDic[itemName] = onUpdateModuleVariableValue; } /// /// 订阅输出变量名称 /// /// public void SubscribeOutput(string itemName) { _outputBag.Add(itemName); } /// /// 订阅主动读取变量名称 /// /// public void SubscribeInput(string itemName) { _inputBag.Add(itemName); } /// /// 初始化 /// /// /// public void Initialize(string ipAddress,int port) { _ipAddress = ipAddress; _port = port; } /// /// 获取所有数据长度 /// /// private int GetAllSize() { int size = 0; foreach(string item in _ioLengthDic.Keys) { size+= _ioLengthDic[item]; } return size; } /// /// ADO变量变化通知,twincat->上位机 /// /// /// private void AdsClient_AdsNotification(object sender, AdsNotificationEventArgs e) { try { if (_notificationHandleNameDic.ContainsKey(e.NotificationHandle)) { string item = _notificationHandleNameDic[e.NotificationHandle]; if(!_ioLengthDic.ContainsKey(item)) { LOG.Write(eEvent.ERR_TWINCAT, "System", $"{item} not in twincat io list"); return; } int size = _ioLengthDic[item]; e.DataStream.Position = e.Offset; if(size==1) { bool boolValue = _reader.ReadBoolean(); if(_moduleVariableActionDic.ContainsKey(item)) { _moduleVariableActionDic[item].Invoke(item, boolValue); } } else if(size==4) { float floatValue= _reader.ReadSingle(); if (_moduleVariableActionDic.ContainsKey(item)) { _moduleVariableActionDic[item].Invoke(item, floatValue); } } else { byte[] byt = new byte[size]; var value = _reader.Read(byt, 0, byt.Length); if (_moduleVariableActionDic.ContainsKey(item)) { _moduleVariableActionDic[item].Invoke(item, byt); } //LOG.Write(eEvent.ERR_TWINCAT, "System", $"{item} size is invalid"); } } } catch (Exception ex) { LOG.Write(eEvent.ERR_TWINCAT, "System", ex.Message); } } /// /// 连接状态变化 /// /// /// private void AdsClient_ConnectionStateChanged(object sender, TwinCAT.ConnectionStateChangedEventArgs e) { if (e.NewState == TwinCAT.ConnectionState.Connected) { try { StateInfo stateInfo = _adsClient.ReadState(); CreateWriteHandle(); CreateReadHandle(); SubscribeNotification(); _isConnected = true; } catch (Exception ex) { _isConnected = false; LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat connect{_ipAddress}:{_port} error"); return; } } else { _isConnected = false; LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat connect{_ipAddress}:{_port} error"); } } /// /// 启动 /// public void Start() { _adsClient = new TcAdsClient(); _adsClient.ConnectionStateChanged += AdsClient_ConnectionStateChanged; _adsClient.AdsNotification += AdsClient_AdsNotification; _adsStream = new AdsStream(GetAllSize()); _reader = new BinaryReader(_adsStream); try { _adsClient.Connect(_ipAddress, _port); } catch { LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat connect{_ipAddress}:{_port} error"); } } /// /// 创建写入句柄 /// private void CreateWriteHandle() { _writeNameHandleDic.Clear(); foreach (string item in _outputBag) { try { int handle = _adsClient.CreateVariableHandle(item); _writeNameHandleDic[item] = handle; } catch { LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat create variable handle {item} error"); } } } /// /// 创建主动读取句柄 /// private void CreateReadHandle() { _readNameHandleDic.Clear(); foreach (string item in _inputBag) { try { int handle = _adsClient.CreateVariableHandle(item); _readNameHandleDic[item] = handle; } catch { LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat create variable handle {item} error"); } } } /// /// 订阅变量 /// private void SubscribeNotification() { _notificationHandleNameDic.Clear(); int count = 0; foreach (string item in _ioLengthDic.Keys) { int size = _ioLengthDic[item]; try { int handle = _adsClient.AddDeviceNotification(item, _adsStream, count, size, AdsTransMode.OnChange, 0, 0, null); _notificationHandleNameDic[handle] = item; count += size; } catch { LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat add variable {item} error"); } } } /// /// 写入数值 /// /// /// /// public (bool success,int status) WriteValue(string name, object value) { if (_writeNameHandleDic.ContainsKey(name)) { if (!_isConnected) { LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat connected failed, write variable {name} error"); return (false,0); } try { int handle = _writeNameHandleDic[name]; _adsClient.WriteAny(handle, value); if (value.ToString() == "System.Byte[]") { byte[] result = ((byte[])value).Where(b => b != 0).ToArray(); string _value = System.Text.Encoding.UTF8.GetString(result); LOG.Write(eEvent.EV_TWINCAT, "System", $"Twincat write variable {name} value {_value}"); } else { LOG.Write(eEvent.EV_TWINCAT, "System", $"Twincat write variable {name} value {value}"); } return (true,0); } catch (Exception ex) { LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat write variable {name} error {ex.Message}"); return (false,1); } } else { LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat doesnot has {name} variable"); return (false, 0); } } /// /// 主动读取 /// /// /// /// public (bool success,object obj) ReadValue(string name,Type type) { if (_readNameHandleDic.ContainsKey(name)) { if (!_isConnected) { LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat connected failed, read variable {name} error"); return (false, null); } try { int handle = _readNameHandleDic[name]; return (true, _adsClient.ReadAny(handle,type)); } catch (Exception ex) { LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat write variable {name} error {ex.Message}"); return (false, null); } } else { LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat doesnot has {name} variable"); return (false, null); } } #region 支持写入结构体 /* T必须字段必须为连续地址, * [StructLayout(LayoutKind.Sequential)] public class Tag { [MarshalAs(UnmanagedType.I1)] public bool DO_PVN21; [MarshalAs(UnmanagedType.I1)] public bool DO_PV11; [MarshalAs(UnmanagedType.R4)] public float AI_Chamber_Pressure_10t; } * */ /// /// 写入类 /// /// /// /// /// public (bool success,int status) WriteStruct(string name,T data) { if (_writeNameHandleDic.ContainsKey(name)) { if (!_isConnected) { LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat connected failed, write variable {name} error"); return (false, 0); } try { int handle = _writeNameHandleDic[name]; _adsClient.WriteAny(handle, data); LOG.Write(eEvent.EV_TWINCAT, "System", $"Twincat write variable {name} value {data}"); return (true, 0); } catch (Exception ex) { LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat write variable {name} error {ex.Message}"); return (false, 1); } } else { LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat doesnot has {name} variable"); return (false, 0); } } #endregion } }