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 内部变量 /// /// ads COE对象 /// private TcAdsClient _adsClientCOE; /// /// Net Id /// private string _netId; /// /// 端口号 /// private int _port; /// /// 轴对象 /// private BeckhoffAxis _axis; /// /// 连接输入变量(连接后读取变量) /// private BeckhoffAxisInput _connectInputVariable; /// /// 连接状态 /// private bool _isConnected = false; /// /// coe输入变量(key-名称,value-输入变量对象) /// private Dictionary _nameCoeInputDic = new Dictionary(); /// /// COE名称变量字典(key-名称,value-输出变量对象) /// private Dictionary _nameCoeOutputDic = new Dictionary(); /// /// 连接是否完成 /// private bool _isConnectComplete = false; /// /// 启动读取线程 /// private Thread _startReadThread = null; #endregion /// /// 模拟 /// /// /// /// public TwincatCoeInterface(BeckhoffAxis beckhoffAxis) { _axis = beckhoffAxis; _netId = beckhoffAxis.COEAddress; _port = beckhoffAxis.COEPort; AnalyseConnectInputVariable(); _adsClientCOE = new TcAdsClient(); _adsClientCOE.ConnectionStateChanged += AdsClientCOE_ConnectionStateChanged; } /// /// 解析连接变量 /// private void AnalyseConnectInputVariable() { foreach(BeckhoffAxisInput item in _axis.Inputs) { if(item.Address.StartsWith("0x")) { _connectInputVariable = item; break; } } } /// /// 初始化输入输出变量 /// 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; } } } /// /// 开启读取变量线程 /// public void StartReadInputDataThread() { if (_startReadThread == null) { _startReadThread = new Thread(new ThreadStart(StartReadInputData)); _startReadThread.IsBackground = true; _startReadThread.Start(); } } /// /// 读取变量 /// 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); } } } /// /// 读取所有COE变量 /// private void ReadAllCoeInputs() { if(_nameCoeInputDic.Keys==null|| _nameCoeInputDic.Count==0) { return; } List 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); } } /// /// 连接状态变化 /// /// /// 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"); } } /// /// 连接 /// /// public void Connect() { try { _adsClientCOE.Connect(_netId, _port); } catch(Exception ex) { LOG.WriteLog(eEvent.ERR_TWINCAT, "System", ex.Message); } } #region 写数据 /// /// 写数据 /// /// /// /// /// 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; } } /// /// 解析Sdo索引 /// /// /// 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); } } } /// /// 写COE Byte数据 /// /// /// /// 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 读数据 /// /// 读取COE Byte数据 /// /// /// /// 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; } } /// /// 读取第一个COE数据 /// /// /// /// /// 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 } }