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
}
}