123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- 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<TwincatAdoManager>
- {
- #region 内部变量
- private TcAdsClient _adsClient = null;
- private string _ipAddress = "";
- private int _port = 851;
- private BeckhoffCfg _cfg;
- private Dictionary<int, BeckhoffItem> _handleItemDic = new Dictionary<int, BeckhoffItem>();
- private Dictionary<string, int> _notificationNameHandleDic = new Dictionary<string, int>();
- private Dictionary<string, int> _writeNameHandleDic = new Dictionary<string, int>();
- private AdsStream _adsStream;
- private BinaryReader _reader;
- private bool _isConnected = false;
- /// <summary>
- /// BitOperated地址数值字典(key-BitOperated为true地址,value-数值)
- /// </summary>
- private Dictionary<string, byte> _bitOperatedAddressValueDic = new Dictionary<string, byte>();
- /// <summary>
- /// BitOperated锁
- /// </summary>
- private object _bitOperatedLocker = new object();
- #endregion
- #region 属性
- public bool IsConnect
- {
- get { return _isConnected; }
- set { _isConnected = value; }
- }
- #endregion
- /// <summary>
- /// 初始化
- /// </summary>
- public void Initialize()
- {
- int size=BeckhoffIOManager.Instance.Size+BeckhoffAxisManager.Instance.Size+BeckhoffCounterManager.Instance.Size;
- Init(BeckhoffManager.Instance.BeckhoffCfg, size+100);
- }
- /// <summary>
- /// 初始化
- /// </summary>
- /// <param name="ipAddress"></param>
- /// <param name="port"></param>
- 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)
- {
- }
- /// <summary>
- /// 连接状态变化
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- 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");
- }
- }
- /// <summary>
- /// 启动
- /// </summary>
- public void Start()
- {
- try
- {
- _adsClient.Connect(_ipAddress, _port);
- }
- catch
- {
- LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"Twincat connect{_cfg.Controller.IPAddress}:{_cfg.Controller.PortAddress} error");
- }
- }
- /// <summary>
- /// 订阅变量
- /// </summary>
- private void SubscribeNotification()
- {
- _notificationNameHandleDic.Clear();
- _handleItemDic.Clear();
- int count = 0;
- List<BeckhoffItem> 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");
- }
- }
- }
- /// <summary>
- /// 创建写入句柄
- /// </summary>
- 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");
- }
- }
- }
- /// <summary>
- /// 写入数值
- /// </summary>
- /// <param name="name"></param>
- /// <param name="value"></param>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// 获取Beckhoff项数值(用于解决BitOperated为true)
- /// </summary>
- /// <param name="name"></param>
- /// <param name="value"></param>
- /// <returns></returns>
- 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;
- }
- }
- /// <summary>
- /// 变量数值发生变化事件
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- 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);
- }
- }
- /// <summary>
- /// 获取模拟数量数值
- /// </summary>
- /// <param name="dataType"></param>
- /// <returns></returns>
- private double GetAnalogValue(string dataType)
- {
- return double.Parse(GetDataTypeValue(dataType).ToString());
- }
- /// <summary>
- /// 获取数据类型数值
- /// </summary>
- /// <param name="dataType"></param>
- /// <returns></returns>
- 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();
- }
- }
- /// <summary>
- /// 停止
- /// </summary>
- 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;
- }
- * */
- /// <summary>
- /// 写入类
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="name"></param>
- /// <param name="data"></param>
- /// <returns></returns>
- public (bool success, int status) WriteStruct<T>(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
- }
- }
|