using Aitex.Core.RT.Event; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.Log; using Aitex.Core.Util; using MECF.Framework.Common.Beckhoff.IOAxis; using MECF.Framework.Common.IOCore; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; using TwinCAT; using TwinCAT.Ads; using TwinCAT.Ads.TypeSystem; using TwinCAT.Ads.ValueAccess; using TwinCAT.TypeSystem; namespace MECF.Framework.Common.TwinCat { public class TwincatAdoManager : Singleton { #region 内部变量 private TcAdsClient _adsClient = null; private string _ipAddress = ""; private int _port = 851; private BeckhoffCfg _cfg; private Dictionary _handleItemDic = new Dictionary(); private Dictionary _notificationNameHandleDic = new Dictionary(); private Dictionary _writeNameHandleDic = new Dictionary(); private AdsStream _adsStream; private BinaryReader _reader; private bool _isConnected = false; /// /// BitOperated地址数值字典(key-BitOperated为true地址,value-数值) /// private Dictionary _bitOperatedAddressValueDic = new Dictionary(); /// /// BitOperated锁 /// private object _bitOperatedLocker = new object(); #endregion #region 属性 public bool IsConnect { get { return _isConnected; } set { _isConnected = value; } } #endregion /// /// 初始化 /// public void Initialize() { int size=BeckhoffIOManager.Instance.Size+BeckhoffAxisManager.Instance.Size+BeckhoffCounterManager.Instance.Size; Init(BeckhoffManager.Instance.BeckhoffCfg, size+100); } /// /// 初始化 /// /// /// private void Init(BeckhoffCfg beckhoffCfg,int size) { _adsClient = new TcAdsClient(); _adsClient.ConnectionStateChanged += AdsClient_ConnectionStateChanged; _cfg = beckhoffCfg; _ipAddress = beckhoffCfg.Controller.IPAddress; _port = int.Parse(beckhoffCfg.Controller.PortAddress); _adsStream = new AdsStream(size); _reader=new BinaryReader(_adsStream); _adsClient.AdsNotification += AdsClient_AdsNotification; _adsClient.AdsNotificationError += AdsClient_AdsNotificationError; Start(); } private void AdsClient_AdsNotificationError(object sender, AdsNotificationErrorEventArgs e) { } /// /// 连接状态变化 /// /// /// private void AdsClient_ConnectionStateChanged(object sender, TwinCAT.ConnectionStateChangedEventArgs e) { LOG.WriteLog(eEvent.INFO_TWINCAT, "System", $"Twincat connect{_cfg.Controller.IPAddress}:{_cfg.Controller.PortAddress} stated changed from {e.OldState} to {e.NewState}"); if (e.NewState==TwinCAT.ConnectionState.Connected) { try { StateInfo stateInfo = _adsClient.ReadState(); CreateWriteHandle(); SubscribeNotification(); _isConnected = true; BeckhoffAxisManager.Instance.StartCoeInterface(); } catch(Exception ex) { _isConnected = false; LOG.WriteLog(eEvent.ERR_TWINCAT,"System",$"Twincat connect{_cfg.Controller.IPAddress}:{_cfg.Controller.PortAddress} error"); return; } } else { _isConnected = false; LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"Twincat connect{_cfg.Controller.IPAddress}:{_cfg.Controller.PortAddress} error"); } } /// /// 启动 /// public void Start() { try { _adsClient.Connect(_ipAddress, _port); } catch { LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"Twincat connect{_cfg.Controller.IPAddress}:{_cfg.Controller.PortAddress} error"); } } /// /// 订阅变量 /// private void SubscribeNotification() { _notificationNameHandleDic.Clear(); _handleItemDic.Clear(); int count = 0; List beckhoffItems = BeckhoffItemManager.Instance.GetIOItems(); foreach(BeckhoffItem item in beckhoffItems) { try { int handle = _adsClient.AddDeviceNotification(item.Address, _adsStream, count, item.Size, AdsTransMode.OnChange, 0, 0, item); _notificationNameHandleDic[item.Name] = handle; _handleItemDic[handle] = item; count += item.Size; } catch(Exception ex) { LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"Twincat add variable {item.Name} error"); } } } /// /// 创建写入句柄 /// private void CreateWriteHandle() { _writeNameHandleDic.Clear(); foreach(BeckhoffItem item in BeckhoffItemManager.Instance.GetWriteItems()) { try { int handle = _adsClient.CreateVariableHandle(item.Address); _writeNameHandleDic[item.Name] = handle; } catch { LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"Twincat create variable handle {item.Name} error"); } } } /// /// 写入数值 /// /// /// /// public bool WriteValue(string name,object value) { if(_writeNameHandleDic.ContainsKey(name)) { if(!_isConnected) { LOG.WriteLog(eEvent.ERR_TWINCAT,"System", $"Twincat connected failed, write variable {name} error"); return false; } int handle = _writeNameHandleDic[name]; BeckhoffItem item = BeckhoffItemManager.Instance.GetIOBeckhoffItem(name); object convertedValue = value; try { if (item != null && item.BitOperated) { if (item.Invert && convertedValue is bool) { convertedValue = !(bool)convertedValue; } lock (_bitOperatedLocker) { convertedValue = GetBeckoffItemValue(item, convertedValue); _adsClient.WriteAny(handle, convertedValue); _bitOperatedAddressValueDic[item.Address] = (byte)convertedValue; } } else { _adsClient.WriteAny(handle, convertedValue); } LOG.WriteLog(eEvent.INFO_TWINCAT, "System", $"Twincat write variable {name} value {convertedValue}"); return true; } catch(Exception ex) { LOG.WriteLog(eEvent.ERR_TWINCAT,"System", $"Twincat write variable {name} error {ex.Message}"); return false; } } else { LOG.WriteLog(eEvent.ERR_TWINCAT,"System", $"Twincat doesnot has {name} variable"); } return false; } /// /// 获取Beckhoff项数值(用于解决BitOperated为true) /// /// /// /// private object GetBeckoffItemValue(BeckhoffItem item,object value) { if (_bitOperatedAddressValueDic.ContainsKey(item.Address)) { byte addressValue = _bitOperatedAddressValueDic[item.Address]; bool[] boolArray = Converter.GetboolArrayByByte(addressValue); bool boolValue = (bool)value; if (item.Bit < boolArray.Length) { boolArray[item.Bit] = boolValue; } byte byt = Converter.GetByteValueByBoolArray(boolArray); return byt; } else { return value; } } /// /// 变量数值发生变化事件 /// /// /// private void AdsClient_AdsNotification(object sender, AdsNotificationEventArgs e) { try { BeckhoffItem item = null; if (_handleItemDic.ContainsKey(e.NotificationHandle)) { item = _handleItemDic[e.NotificationHandle]; } else { item = (BeckhoffItem)e.UserData; } e.DataStream.Position = e.Offset; if (item != null) { switch (item.IoType) { case "di": BeckhoffDIAccessor diAccessor = BeckhoffIOManager.Instance.GetDIAccessor(item.Name); if (diAccessor != null) { diAccessor.Value = _reader.ReadBoolean(); if (item.Invert) { IOModuleManager.Instance.UpdateIoValue(item.Name, !diAccessor.Value); } else { IOModuleManager.Instance.UpdateIoValue(item.Name, diAccessor.Value); } } break; case "do": BeckhoffDOAccessor doAccessor = BeckhoffIOManager.Instance.GetDOAccessor(item.Name); if (doAccessor != null) { if (item.BitOperated) { byte byt = _reader.ReadByte(); lock (_bitOperatedLocker) { _bitOperatedAddressValueDic[doAccessor.Address] = byt; } doAccessor.Value = ((byt >> item.Bit) & 0x01) == 0x01; } else { doAccessor.Value = _reader.ReadBoolean(); } if (item.Invert) { IOModuleManager.Instance.UpdateIoValue(item.Name, !doAccessor.Value); } else { IOModuleManager.Instance.UpdateIoValue(item.Name, doAccessor.Value); } } break; case "ai": BeckhoffAIAccessor aiAccessor = BeckhoffIOManager.Instance.GetAIAccessor(item.Name); if (aiAccessor != null) { double twincatValue = GetAnalogValue(item.DataType); var result = ScalingManager.Instance.CalculateValueByTwincatVariable(item.Name, twincatValue); if (result.Item1) { aiAccessor.Value = result.Item2; } else { aiAccessor.Value = twincatValue; } IOModuleManager.Instance.UpdateIoValue(item.Name, aiAccessor.Value); } break; case "ao": BeckhoffAOAccessor aoAccessor = BeckhoffIOManager.Instance.GetAOAccesssor(item.Name); if (aoAccessor != null) { double twincatValue = GetAnalogValue(item.DataType); var result = ScalingManager.Instance.CalculateValueByTwincatVariable(item.Name, twincatValue); if (result.Item1) { aoAccessor.Value = result.Item2; } else { aoAccessor.Value = twincatValue; } IOModuleManager.Instance.UpdateIoValue(item.Name, aoAccessor.Value); } break; case "axis": object itemValue = GetDataTypeValue(item.DataType); if (item.Invert) { bool boolValue = (bool)itemValue; BeckhoffAxisManager.Instance.SetAxisValue(item.Name, !boolValue); } else { BeckhoffAxisManager.Instance.SetAxisValue(item.Name, itemValue); } break; case "counter": if (item.Invert) { object counterItemValue = GetDataTypeValue(item.DataType); bool boolValue = (bool)counterItemValue; BeckhoffCounterManager.Instance.SetCounterValue(item.Name, !boolValue); } else { object counterItemValue = GetDataTypeValue(item.DataType); BeckhoffCounterManager.Instance.SetCounterValue(item.Name, counterItemValue); } break; } } } catch(Exception ex) { LOG.WriteLog(eEvent.ERR_TWINCAT, "System", ex.Message); } } /// /// 获取模拟数量数值 /// /// /// private double GetAnalogValue(string dataType) { return double.Parse(GetDataTypeValue(dataType).ToString()); } /// /// 获取数据类型数值 /// /// /// private object GetDataTypeValue(string dataType) { switch (dataType) { case "byte": return _reader.ReadByte(); case "sint": return _reader.ReadSByte(); case "usint": return _reader.ReadByte(); case "short": return _reader.ReadInt16(); case "int": return _reader.ReadInt16(); case "uint": return _reader.ReadUInt16(); case "dint": return _reader.ReadInt32(); case "udint": return _reader.ReadUInt32(); case "long": return _reader.ReadInt64(); case "float": return _reader.ReadSingle(); case "ulong": return _reader.ReadUInt64(); case "double": return _reader.ReadDouble(); case "bool": return _reader.ReadBoolean(); default: return _reader.ReadDouble(); } } /// /// 停止 /// public void Stop() { _adsClient.Dispose(); } #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.WriteLog(eEvent.ERR_TWINCAT, "System", $"Twincat connected failed, write variable {name} error"); return (false, 0); } try { int handle = _writeNameHandleDic[name]; _adsClient.WriteAny(handle, data); LOG.WriteLog(eEvent.INFO_TWINCAT, "System", $"Twincat write variable {name} value {data}"); return (true, 0); } catch (Exception ex) { LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"Twincat write variable {name} error {ex.Message}"); return (false, 1); } } else { LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"Twincat doesnot has {name} variable"); return (false, 0); } } #endregion } }