123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- using Aitex.Core.RT.Log;
- using MECF.Framework.Common.Beckhoff.IOAxis;
- using MECF.Framework.Common.Utilities;
- using System;
- using System.Collections.Generic;
- using System.Globalization;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- using TwinCAT.Ads;
- namespace MECF.Framework.Common.TwinCat
- {
- public class TwincatCoeInterface
- {
- #region 常量
- private const int INDEXGROUP_SDO_UPLOAD_DOWNLOAD = 0x0000f302;
- #endregion
- #region 内部变量
- /// <summary>
- /// ads COE对象
- /// </summary>
- private TcAdsClient _adsClientCOE;
- /// <summary>
- /// Net Id
- /// </summary>
- private string _netId;
- /// <summary>
- /// 端口号
- /// </summary>
- private int _port;
- /// <summary>
- /// 轴对象
- /// </summary>
- private BeckhoffAxis _axis;
- /// <summary>
- /// 连接输入变量(连接后读取变量)
- /// </summary>
- private BeckhoffAxisInput _connectInputVariable;
- /// <summary>
- /// 连接状态
- /// </summary>
- private bool _isConnected = false;
- /// <summary>
- /// coe输入变量(key-名称,value-输入变量对象)
- /// </summary>
- private Dictionary<string,BeckhoffAxisInput> _nameCoeInputDic = new Dictionary<string, BeckhoffAxisInput>();
- /// <summary>
- /// COE名称变量字典(key-名称,value-输出变量对象)
- /// </summary>
- private Dictionary<string, BeckhoffAxisOutput> _nameCoeOutputDic = new Dictionary<string, BeckhoffAxisOutput>();
- /// <summary>
- /// 连接是否完成
- /// </summary>
- private bool _isConnectComplete = false;
- /// <summary>
- /// 启动读取线程
- /// </summary>
- private Thread _startReadThread = null;
- #endregion
- /// <summary>
- /// 模拟
- /// </summary>
- /// <param name="moduleName"></param>
- /// <param name="netId"></param>
- /// <param name="port"></param>
- public TwincatCoeInterface(BeckhoffAxis beckhoffAxis)
- {
- _axis = beckhoffAxis;
- _netId = beckhoffAxis.COEAddress;
- _port = beckhoffAxis.COEPort;
- AnalyseConnectInputVariable();
- _adsClientCOE = new TcAdsClient();
- _adsClientCOE.ConnectionStateChanged += AdsClientCOE_ConnectionStateChanged;
- }
- /// <summary>
- /// 解析连接变量
- /// </summary>
- private void AnalyseConnectInputVariable()
- {
- foreach(BeckhoffAxisInput item in _axis.Inputs)
- {
- if(item.Address.StartsWith("0x"))
- {
- _connectInputVariable = item;
- break;
- }
- }
- }
- /// <summary>
- /// 初始化输入输出变量
- /// </summary>
- public void InnitialInputAndOutputVariable(BeckhoffAxis beckhoffAxis)
- {
- foreach (BeckhoffAxisInput item in beckhoffAxis.Inputs)
- {
- if (item.Address.StartsWith("0x"))
- {
- _nameCoeInputDic[$"{beckhoffAxis.Name}.{item.Type}"] = item;
- }
- }
- foreach(BeckhoffAxisOutput item in beckhoffAxis.Outputs)
- {
- if (item.Address.StartsWith("0x"))
- {
- _nameCoeOutputDic[$"{beckhoffAxis.Name}.{item.Type}"] = item;
- }
- }
- }
- /// <summary>
- /// 开启读取变量线程
- /// </summary>
- public void StartReadInputDataThread()
- {
- if (_startReadThread == null)
- {
- _startReadThread = new Thread(new ThreadStart(StartReadInputData));
- _startReadThread.IsBackground = true;
- _startReadThread.Start();
- }
- }
- /// <summary>
- /// 读取变量
- /// </summary>
- private void StartReadInputData()
- {
- DateTime dt = DateTime.Now;
- while(true)
- {
- if(DateTime.Now.Subtract(dt).TotalSeconds>=5)
- {
- break;
- }
- if(!_isConnectComplete)
- {
- continue;
- }
- if(!_isConnected)
- {
- continue;
- }
- if (_nameCoeInputDic.Count != 0)
- {
- ReadAllCoeInputs();
- break;
- }
- else
- {
- Thread.Sleep(500);
- }
- }
-
- }
- /// <summary>
- /// 读取所有COE变量
- /// </summary>
- private void ReadAllCoeInputs()
- {
- if(_nameCoeInputDic.Keys==null|| _nameCoeInputDic.Count==0)
- {
- return;
- }
- List<string> keys = _nameCoeInputDic.Keys.ToList();
- foreach (string key in keys)
- {
- BeckhoffAxisInput item = _nameCoeInputDic[key];
- Type type = DataTypeUtil.GetSystemDataTypeByBeckhoffDataType(item.DataType);
- var sdoResult = AnalyseSdoIndex(item.Address);
- if (sdoResult.Item1)
- {
- object value = ReadCOEData(sdoResult.Item2, sdoResult.Item3, type);
- if (value != null)
- {
- BeckhoffAxisManager.Instance.SetAxisValue(key, value);
- }
- else
- {
- LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"read {key} error");
- }
- }
- Thread.Sleep(10);
- }
- }
- /// <summary>
- /// 连接状态变化
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void AdsClientCOE_ConnectionStateChanged(object sender, TwinCAT.ConnectionStateChangedEventArgs e)
- {
- if (e.NewState == TwinCAT.ConnectionState.Connected)
- {
- try
- {
- if (_connectInputVariable != null)
- {
- var inputResult = AnalyseSdoIndex(_connectInputVariable.Address);
- if (inputResult.Item1)
- {
- object obj= ReadFirstCOEData(inputResult.Item2, inputResult.Item3, DataTypeUtil.GetSystemDataTypeByBeckhoffDataType(_connectInputVariable.DataType));
- if (obj != null)
- {
- _isConnected = true;
- _isConnectComplete = true;
- }
- }
- }
- }
- catch (Exception ex)
- {
- _isConnectComplete = true;
- _isConnected = false;
- LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"Twincat connect{_netId}:{_port} error");
- return;
- }
- }
- else
- {
- _isConnected = false;
- LOG.WriteLog(eEvent.ERR_TWINCAT,"System", $"Twincat connect{_netId}:{_port} error");
- }
- }
- /// <summary>
- /// 连接
- /// </summary>
- /// <returns></returns>
- public void Connect()
- {
- try
- {
- _adsClientCOE.Connect(_netId, _port);
- }
- catch(Exception ex)
- {
- LOG.WriteLog(eEvent.ERR_TWINCAT, "System", ex.Message);
- }
- }
- #region 写数据
- /// <summary>
- /// 写数据
- /// </summary>
- /// <param name="moduleName"></param>
- /// <param name="variableName"></param>
- /// <param name="value"></param>
- /// <returns></returns>
- public bool WriteModuleCoeData(string moduleName,string variableName,object value)
- {
- if(_isConnected)
- {
- string str = $"{moduleName}.{variableName}";
- if(_nameCoeOutputDic.ContainsKey(str))
- {
- BeckhoffAxisOutput output = _nameCoeOutputDic[str];
- try
- {
- var sdoResult = AnalyseSdoIndex(output.Address);
- if(sdoResult.Item1)
- {
- bool result=WriteCOEData(sdoResult.Item2, sdoResult.Item3, value);
- if (result&&_nameCoeInputDic.ContainsKey(str))
- {
- object rdValue = ReadCOEData(sdoResult.Item2, sdoResult.Item3, DataTypeUtil.GetSystemDataTypeByBeckhoffDataType(output.DataType));
- if (rdValue != null)
- {
- BeckhoffAxisManager.Instance.SetAxisValue(str, rdValue);
- }
- }
- return true;
- }
- else
- {
- return false;
- }
- }
- catch(Exception ex)
- {
- LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"twincat cannot write COE data, message is [{ex.Message}]");
- return false;
- }
- }
- else
- {
- LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"twincat doesnot have [{moduleName}.{variableName}] variable ,cannot write COE data");
- return false;
- }
- }
- else
- {
- LOG.WriteLog(eEvent.ERR_TWINCAT, "System", "twincat connect failed,cannot write COE data");
- return false;
- }
- }
- /// <summary>
- /// 解析Sdo索引
- /// </summary>
- /// <param name="address"></param>
- /// <returns></returns>
- private (bool,int,int) AnalyseSdoIndex(string address)
- {
- string[] strAry = address.Split(':');
- if (strAry.Length != 2)
- {
- LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"twincat invalid address is {address}");
- return (false,0,0);
- }
- else
- {
-
- if (int.TryParse(strAry[0].Remove(0,2), System.Globalization.NumberStyles.HexNumber, System.Globalization.NumberFormatInfo.InvariantInfo, out int sdoIndex) &&
- int.TryParse(strAry[1], out int sdoSubIndex))
- {
- return (true,sdoIndex,sdoSubIndex);
- }
- else
- {
- LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"twincat invalid address is {address}");
- return (false,0,0);
- }
- }
- }
- /// <summary>
- /// 写COE Byte数据
- /// </summary>
- /// <param name="sdoIndex"></param>
- /// <param name="sdoSubIndex"></param>
- /// <param name="value"></param>
- private bool WriteCOEData(int sdoIndex,int sdoSubIndex,object value)
- {
- if (_isConnected)
- {
- int indexOffset = (int)sdoIndex * 65536 + sdoSubIndex;
- try
- {
- _adsClientCOE.WriteAny(INDEXGROUP_SDO_UPLOAD_DOWNLOAD, indexOffset, value);
- return true;
- }
- catch (Exception ex)
- {
- LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"twincat write COE data failed {ex.Message}.IndexOffset:{sdoIndex}:{sdoSubIndex}");
- return false;
- }
- }
- else
- {
- LOG.WriteLog(eEvent.ERR_TWINCAT, "System", "twincat connect failed,cannot write COE data");
- return false;
- }
- }
- #endregion
- #region 读数据
- /// <summary>
- /// 读取COE Byte数据
- /// </summary>
- /// <param name="sdoIndex"></param>
- /// <param name="sdoSubIndex"></param>
- /// <returns></returns>
- public object ReadCOEData(int sdoIndex,int sdoSubIndex,Type type)
- {
- if (_isConnected)
- {
- int indexOffset = (int)sdoIndex * 65536 + sdoSubIndex;
- try
- {
- return _adsClientCOE.ReadAny(INDEXGROUP_SDO_UPLOAD_DOWNLOAD, indexOffset, type);
- }
- catch(Exception ex)
- {
- LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"twincat read COE data failed {ex.Message}.IndexOffset:{sdoIndex}:{sdoSubIndex}");
- return null;
- }
- }
- else
- {
- LOG.WriteLog(eEvent.ERR_TWINCAT, "System", "twincat connect failed,cannot read COE data");
- return null;
- }
- }
- /// <summary>
- /// 读取第一个COE数据
- /// </summary>
- /// <param name="sdoIndex"></param>
- /// <param name="sdoSubIndex"></param>
- /// <param name="type"></param>
- /// <returns></returns>
- private object ReadFirstCOEData(int sdoIndex, int sdoSubIndex, Type type)
- {
- int indexOffset = (int)sdoIndex * 65536 + sdoSubIndex;
- try
- {
- return _adsClientCOE.ReadAny(INDEXGROUP_SDO_UPLOAD_DOWNLOAD, indexOffset, type);
- }
- catch (Exception ex)
- {
- LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"twincat read COE data failed {ex.Message}.IndexOffset:{sdoIndex}:{sdoSubIndex}");
- return null;
- }
- }
- #endregion
- }
- }
|