TwincatCoeInterface.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. using Aitex.Core.RT.Log;
  2. using MECF.Framework.Common.Beckhoff.IOAxis;
  3. using MECF.Framework.Common.Utilities;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Globalization;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. using TwinCAT.Ads;
  12. namespace MECF.Framework.Common.TwinCat
  13. {
  14. public class TwincatCoeInterface
  15. {
  16. #region 常量
  17. private const int INDEXGROUP_SDO_UPLOAD_DOWNLOAD = 0x0000f302;
  18. #endregion
  19. #region 内部变量
  20. /// <summary>
  21. /// ads COE对象
  22. /// </summary>
  23. private TcAdsClient _adsClientCOE;
  24. /// <summary>
  25. /// Net Id
  26. /// </summary>
  27. private string _netId;
  28. /// <summary>
  29. /// 端口号
  30. /// </summary>
  31. private int _port;
  32. /// <summary>
  33. /// 轴对象
  34. /// </summary>
  35. private BeckhoffAxis _axis;
  36. /// <summary>
  37. /// 连接输入变量(连接后读取变量)
  38. /// </summary>
  39. private BeckhoffAxisInput _connectInputVariable;
  40. /// <summary>
  41. /// 连接状态
  42. /// </summary>
  43. private bool _isConnected = false;
  44. /// <summary>
  45. /// coe输入变量(key-名称,value-输入变量对象)
  46. /// </summary>
  47. private Dictionary<string,BeckhoffAxisInput> _nameCoeInputDic = new Dictionary<string, BeckhoffAxisInput>();
  48. /// <summary>
  49. /// COE名称变量字典(key-名称,value-输出变量对象)
  50. /// </summary>
  51. private Dictionary<string, BeckhoffAxisOutput> _nameCoeOutputDic = new Dictionary<string, BeckhoffAxisOutput>();
  52. /// <summary>
  53. /// 连接是否完成
  54. /// </summary>
  55. private bool _isConnectComplete = false;
  56. /// <summary>
  57. /// 启动读取线程
  58. /// </summary>
  59. private Thread _startReadThread = null;
  60. #endregion
  61. /// <summary>
  62. /// 模拟
  63. /// </summary>
  64. /// <param name="moduleName"></param>
  65. /// <param name="netId"></param>
  66. /// <param name="port"></param>
  67. public TwincatCoeInterface(BeckhoffAxis beckhoffAxis)
  68. {
  69. _axis = beckhoffAxis;
  70. _netId = beckhoffAxis.COEAddress;
  71. _port = beckhoffAxis.COEPort;
  72. AnalyseConnectInputVariable();
  73. _adsClientCOE = new TcAdsClient();
  74. _adsClientCOE.ConnectionStateChanged += AdsClientCOE_ConnectionStateChanged;
  75. }
  76. /// <summary>
  77. /// 解析连接变量
  78. /// </summary>
  79. private void AnalyseConnectInputVariable()
  80. {
  81. foreach(BeckhoffAxisInput item in _axis.Inputs)
  82. {
  83. if(item.Address.StartsWith("0x"))
  84. {
  85. _connectInputVariable = item;
  86. break;
  87. }
  88. }
  89. }
  90. /// <summary>
  91. /// 初始化输入输出变量
  92. /// </summary>
  93. public void InnitialInputAndOutputVariable(BeckhoffAxis beckhoffAxis)
  94. {
  95. foreach (BeckhoffAxisInput item in beckhoffAxis.Inputs)
  96. {
  97. if (item.Address.StartsWith("0x"))
  98. {
  99. _nameCoeInputDic[$"{beckhoffAxis.Name}.{item.Type}"] = item;
  100. }
  101. }
  102. foreach(BeckhoffAxisOutput item in beckhoffAxis.Outputs)
  103. {
  104. if (item.Address.StartsWith("0x"))
  105. {
  106. _nameCoeOutputDic[$"{beckhoffAxis.Name}.{item.Type}"] = item;
  107. }
  108. }
  109. }
  110. /// <summary>
  111. /// 开启读取变量线程
  112. /// </summary>
  113. public void StartReadInputDataThread()
  114. {
  115. if (_startReadThread == null)
  116. {
  117. _startReadThread = new Thread(new ThreadStart(StartReadInputData));
  118. _startReadThread.IsBackground = true;
  119. _startReadThread.Start();
  120. }
  121. }
  122. /// <summary>
  123. /// 读取变量
  124. /// </summary>
  125. private void StartReadInputData()
  126. {
  127. DateTime dt = DateTime.Now;
  128. while(true)
  129. {
  130. if(DateTime.Now.Subtract(dt).TotalSeconds>=5)
  131. {
  132. break;
  133. }
  134. if(!_isConnectComplete)
  135. {
  136. continue;
  137. }
  138. if(!_isConnected)
  139. {
  140. continue;
  141. }
  142. if (_nameCoeInputDic.Count != 0)
  143. {
  144. ReadAllCoeInputs();
  145. break;
  146. }
  147. else
  148. {
  149. Thread.Sleep(500);
  150. }
  151. }
  152. }
  153. /// <summary>
  154. /// 读取所有COE变量
  155. /// </summary>
  156. private void ReadAllCoeInputs()
  157. {
  158. if(_nameCoeInputDic.Keys==null|| _nameCoeInputDic.Count==0)
  159. {
  160. return;
  161. }
  162. List<string> keys = _nameCoeInputDic.Keys.ToList();
  163. foreach (string key in keys)
  164. {
  165. BeckhoffAxisInput item = _nameCoeInputDic[key];
  166. Type type = DataTypeUtil.GetSystemDataTypeByBeckhoffDataType(item.DataType);
  167. var sdoResult = AnalyseSdoIndex(item.Address);
  168. if (sdoResult.Item1)
  169. {
  170. object value = ReadCOEData(sdoResult.Item2, sdoResult.Item3, type);
  171. if (value != null)
  172. {
  173. BeckhoffAxisManager.Instance.SetAxisValue(key, value);
  174. }
  175. else
  176. {
  177. LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"read {key} error");
  178. }
  179. }
  180. Thread.Sleep(10);
  181. }
  182. }
  183. /// <summary>
  184. /// 连接状态变化
  185. /// </summary>
  186. /// <param name="sender"></param>
  187. /// <param name="e"></param>
  188. private void AdsClientCOE_ConnectionStateChanged(object sender, TwinCAT.ConnectionStateChangedEventArgs e)
  189. {
  190. if (e.NewState == TwinCAT.ConnectionState.Connected)
  191. {
  192. try
  193. {
  194. if (_connectInputVariable != null)
  195. {
  196. var inputResult = AnalyseSdoIndex(_connectInputVariable.Address);
  197. if (inputResult.Item1)
  198. {
  199. object obj= ReadFirstCOEData(inputResult.Item2, inputResult.Item3, DataTypeUtil.GetSystemDataTypeByBeckhoffDataType(_connectInputVariable.DataType));
  200. if (obj != null)
  201. {
  202. _isConnected = true;
  203. _isConnectComplete = true;
  204. }
  205. }
  206. }
  207. }
  208. catch (Exception ex)
  209. {
  210. _isConnectComplete = true;
  211. _isConnected = false;
  212. LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"Twincat connect{_netId}:{_port} error");
  213. return;
  214. }
  215. }
  216. else
  217. {
  218. _isConnected = false;
  219. LOG.WriteLog(eEvent.ERR_TWINCAT,"System", $"Twincat connect{_netId}:{_port} error");
  220. }
  221. }
  222. /// <summary>
  223. /// 连接
  224. /// </summary>
  225. /// <returns></returns>
  226. public void Connect()
  227. {
  228. try
  229. {
  230. _adsClientCOE.Connect(_netId, _port);
  231. }
  232. catch(Exception ex)
  233. {
  234. LOG.WriteLog(eEvent.ERR_TWINCAT, "System", ex.Message);
  235. }
  236. }
  237. #region 写数据
  238. /// <summary>
  239. /// 写数据
  240. /// </summary>
  241. /// <param name="moduleName"></param>
  242. /// <param name="variableName"></param>
  243. /// <param name="value"></param>
  244. /// <returns></returns>
  245. public bool WriteModuleCoeData(string moduleName,string variableName,object value)
  246. {
  247. if(_isConnected)
  248. {
  249. string str = $"{moduleName}.{variableName}";
  250. if(_nameCoeOutputDic.ContainsKey(str))
  251. {
  252. BeckhoffAxisOutput output = _nameCoeOutputDic[str];
  253. try
  254. {
  255. var sdoResult = AnalyseSdoIndex(output.Address);
  256. if(sdoResult.Item1)
  257. {
  258. bool result=WriteCOEData(sdoResult.Item2, sdoResult.Item3, value);
  259. if (result&&_nameCoeInputDic.ContainsKey(str))
  260. {
  261. object rdValue = ReadCOEData(sdoResult.Item2, sdoResult.Item3, DataTypeUtil.GetSystemDataTypeByBeckhoffDataType(output.DataType));
  262. if (rdValue != null)
  263. {
  264. BeckhoffAxisManager.Instance.SetAxisValue(str, rdValue);
  265. }
  266. }
  267. return true;
  268. }
  269. else
  270. {
  271. return false;
  272. }
  273. }
  274. catch(Exception ex)
  275. {
  276. LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"twincat cannot write COE data, message is [{ex.Message}]");
  277. return false;
  278. }
  279. }
  280. else
  281. {
  282. LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"twincat doesnot have [{moduleName}.{variableName}] variable ,cannot write COE data");
  283. return false;
  284. }
  285. }
  286. else
  287. {
  288. LOG.WriteLog(eEvent.ERR_TWINCAT, "System", "twincat connect failed,cannot write COE data");
  289. return false;
  290. }
  291. }
  292. /// <summary>
  293. /// 解析Sdo索引
  294. /// </summary>
  295. /// <param name="address"></param>
  296. /// <returns></returns>
  297. private (bool,int,int) AnalyseSdoIndex(string address)
  298. {
  299. string[] strAry = address.Split(':');
  300. if (strAry.Length != 2)
  301. {
  302. LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"twincat invalid address is {address}");
  303. return (false,0,0);
  304. }
  305. else
  306. {
  307. if (int.TryParse(strAry[0].Remove(0,2), System.Globalization.NumberStyles.HexNumber, System.Globalization.NumberFormatInfo.InvariantInfo, out int sdoIndex) &&
  308. int.TryParse(strAry[1], out int sdoSubIndex))
  309. {
  310. return (true,sdoIndex,sdoSubIndex);
  311. }
  312. else
  313. {
  314. LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"twincat invalid address is {address}");
  315. return (false,0,0);
  316. }
  317. }
  318. }
  319. /// <summary>
  320. /// 写COE Byte数据
  321. /// </summary>
  322. /// <param name="sdoIndex"></param>
  323. /// <param name="sdoSubIndex"></param>
  324. /// <param name="value"></param>
  325. private bool WriteCOEData(int sdoIndex,int sdoSubIndex,object value)
  326. {
  327. if (_isConnected)
  328. {
  329. int indexOffset = (int)sdoIndex * 65536 + sdoSubIndex;
  330. try
  331. {
  332. _adsClientCOE.WriteAny(INDEXGROUP_SDO_UPLOAD_DOWNLOAD, indexOffset, value);
  333. return true;
  334. }
  335. catch (Exception ex)
  336. {
  337. LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"twincat write COE data failed {ex.Message}.IndexOffset:{sdoIndex}:{sdoSubIndex}");
  338. return false;
  339. }
  340. }
  341. else
  342. {
  343. LOG.WriteLog(eEvent.ERR_TWINCAT, "System", "twincat connect failed,cannot write COE data");
  344. return false;
  345. }
  346. }
  347. #endregion
  348. #region 读数据
  349. /// <summary>
  350. /// 读取COE Byte数据
  351. /// </summary>
  352. /// <param name="sdoIndex"></param>
  353. /// <param name="sdoSubIndex"></param>
  354. /// <returns></returns>
  355. public object ReadCOEData(int sdoIndex,int sdoSubIndex,Type type)
  356. {
  357. if (_isConnected)
  358. {
  359. int indexOffset = (int)sdoIndex * 65536 + sdoSubIndex;
  360. try
  361. {
  362. return _adsClientCOE.ReadAny(INDEXGROUP_SDO_UPLOAD_DOWNLOAD, indexOffset, type);
  363. }
  364. catch(Exception ex)
  365. {
  366. LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"twincat read COE data failed {ex.Message}.IndexOffset:{sdoIndex}:{sdoSubIndex}");
  367. return null;
  368. }
  369. }
  370. else
  371. {
  372. LOG.WriteLog(eEvent.ERR_TWINCAT, "System", "twincat connect failed,cannot read COE data");
  373. return null;
  374. }
  375. }
  376. /// <summary>
  377. /// 读取第一个COE数据
  378. /// </summary>
  379. /// <param name="sdoIndex"></param>
  380. /// <param name="sdoSubIndex"></param>
  381. /// <param name="type"></param>
  382. /// <returns></returns>
  383. private object ReadFirstCOEData(int sdoIndex, int sdoSubIndex, Type type)
  384. {
  385. int indexOffset = (int)sdoIndex * 65536 + sdoSubIndex;
  386. try
  387. {
  388. return _adsClientCOE.ReadAny(INDEXGROUP_SDO_UPLOAD_DOWNLOAD, indexOffset, type);
  389. }
  390. catch (Exception ex)
  391. {
  392. LOG.WriteLog(eEvent.ERR_TWINCAT, "System", $"twincat read COE data failed {ex.Message}.IndexOffset:{sdoIndex}:{sdoSubIndex}");
  393. return null;
  394. }
  395. }
  396. #endregion
  397. }
  398. }