using FestoDebugger.Service; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using TwinCAT.Ads; namespace FestoDebugger.Beckoff { 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; } } /// /// Twincat断开连接 /// public event BeckhoffDelegate.OnNotifyTwincateDisConnect OnTwincateDisConnect; #endregion /// /// 初始化 /// public void Initialize() { Init(BeckhoffManager.Instance.BeckhoffCfg, 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) { if (e.NewState == TwinCAT.ConnectionState.Connected) { try { StateInfo stateInfo = _adsClient.ReadState(); CreateWriteHandle(); SubscribeNotification(); _isConnected = true; } catch (Exception ex) { if (OnTwincateDisConnect != null) { OnTwincateDisConnect(); } _isConnected = false; return; } } else { _isConnected = false; } } /// /// 启动 /// public void Start() { try { _adsClient.Connect(_ipAddress, _port); } catch { } } /// /// 订阅变量 /// 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) { } } } /// /// 创建写入句柄 /// private void CreateWriteHandle() { _writeNameHandleDic.Clear(); foreach (BeckhoffItem item in BeckhoffItemManager.Instance.GetIOItems()) { try { int handle = _adsClient.CreateVariableHandle(item.Address); _writeNameHandleDic[item.Name] = handle; } catch { } } } /// /// 写入数值 /// /// /// /// public bool WriteValue(string name, object value) { if (_writeNameHandleDic.ContainsKey(name)) { if (!_isConnected) { 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); } return true; } catch (Exception ex) { return false; } } else { } 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) { BeckhoffIOManager.Instance.UpdateIoValue(item.Name, !diAccessor.Value); } else { BeckhoffIOManager.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) { BeckhoffIOManager.Instance.UpdateIoValue(item.Name, !doAccessor.Value); } else { BeckhoffIOManager.Instance.UpdateIoValue(item.Name, doAccessor.Value); } } break; } } } catch (Exception ex) { } } /// /// 获取模拟数量数值 /// /// /// 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) { return (false, 0); } try { int handle = _writeNameHandleDic[name]; _adsClient.WriteAny(handle, data); return (true, 0); } catch (Exception ex) { return (false, 1); } } else { return (false, 0); } } #endregion } }