WagoSocketSimulator.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. using Aitex.Common.Util;
  2. using Aitex.Core.RT.Device;
  3. using Aitex.Core.RT.Log;
  4. using Aitex.Core.Util;
  5. using MECF.Framework.Common.Device.Festo;
  6. using MECF.Framework.Common.Device.Wago;
  7. using MECF.Framework.Common.Net;
  8. using MECF.Framework.Common.Simulator;
  9. using MECF.Framework.Simulator.Core.Driver;
  10. using System;
  11. using System.Collections.Generic;
  12. using System.IO;
  13. namespace CyberX8_Simulator.Devices
  14. {
  15. public class WagoSocketSimulator : SocketDeviceSimulator
  16. {
  17. private const short WRITE_DO_STARTADDRESS = 0x0200;
  18. private const short WRITE_AO_STARTADDRESS = 0x0200;
  19. //键是名字,值是对应数据所在的位置 注意:要和WagoControlCfg里面的地址顺序对上
  20. public Dictionary<string, int> DONameIndexDic;
  21. public Dictionary<string, int> DINameIndexDic;
  22. public Dictionary<string, int> AINameIndexDic;
  23. public Dictionary<string, int> AONameIndexDic;
  24. private IByteTransform byteTransform = new BigEndianByteTransformBase();
  25. //存储模拟器数据的数组
  26. public byte[] DOBytes = new byte[100];
  27. public short[] AOShorts = new short[100];
  28. public byte[] DIBytes = new byte[100];
  29. public short[] AIShorts = new short[100];
  30. /// <summary>
  31. /// 写DO锁
  32. /// </summary>
  33. private object _writeDOLocker = new object();
  34. /// <summary>
  35. /// 写AO锁
  36. /// </summary>
  37. private object _writeAOLocker = new object();
  38. public WagoSocketSimulator(int port):base(port)
  39. {
  40. SimulatorCommManager.Instance.OnUpdateVariableValueChanged += UpdataDataCausedByOtherModule;
  41. MotorSimulator.Instance.OnUpdateWagoDatasChanged += UpdataDataCausedByOtherModule;
  42. InitializeData(port);
  43. }
  44. private void UpdataDataCausedByOtherModule(string name, bool value, bool invert)
  45. {
  46. value = invert ? !value : value;
  47. if (AINameIndexDic.ContainsKey(name))
  48. {
  49. switch (name)
  50. {
  51. case "r_LoaderA_LS_Vacuum_anlg":
  52. case "r_LoaderB_LS_Vacuum_anlg":
  53. AIShorts[AINameIndexDic[name]] = value ? (short)0x32C8 : (short)0x2AF8;
  54. break;
  55. case "r_DPUF_A_CHUCK_A_VAC":
  56. case "r_DPUF_A_CHUCK_B_VAC":
  57. AIShorts[AINameIndexDic[name]] = value ? (short)0x0C80 : (short)0x32C8;
  58. break;
  59. case "r_LOADERA_BERNOULLI_PRESSURE":
  60. case "r_LOADERB_BERNOULLI_PRESSURE":
  61. case "r_LOADERA_CHUCK_BLADDER":
  62. case "r_LOADERB_CHUCK_BLADDER":
  63. case "r_LOADERA_WS_BLADDER_PRESSURE":
  64. case "r_LOADERB_WS_BLADDER_PRESSURE":
  65. AIShorts[AINameIndexDic[name]] = value ? (short)0x2AF8 : (short)0x00;
  66. break;
  67. default:
  68. break;
  69. }
  70. }
  71. //DI
  72. UpdataDIBytes(name, value ? 1 : 0);
  73. }
  74. /// <summary>
  75. /// 触发Wago对应数据更新
  76. /// </summary>
  77. /// <param name="position"></param>
  78. /// <param name="value"></param>
  79. private void UpdateDataCausedByWago(int position, bool value)
  80. {
  81. if (position == DONameIndexDic["c_PUF_CHUCK"])
  82. {
  83. UpdataDIBytes("r_PUF_A_CHUCK_OUT", value ? 1 : 0);
  84. UpdataDIBytes("r_PUF_B_CHUCK_OUT", value ? 1 : 0);
  85. UpdataDIBytes("r_PUF_A_CHUCK_IN", !value ? 1 : 0);
  86. UpdataDIBytes("r_PUF_B_CHUCK_IN", !value ? 1 : 0);
  87. }
  88. }
  89. /// <summary>
  90. /// 初始化字典
  91. /// </summary>
  92. private void InitializeData(int port) //端口用于初始化不同Wago设备的字典
  93. {
  94. //加载对应配置文件 WagoControllerCfg-Simulator.xml
  95. try
  96. {
  97. string oldXmlPath = PathManager.GetCfgDir();
  98. string newXmlPath = oldXmlPath.Replace("CyberX8_Simulator", "CyberX8_RT") + "Devices\\WagoControllerCfg-Simulator.xml";
  99. WagoControllerCfg cfg = CustomXmlSerializer.Deserialize<WagoControllerCfg>(new FileInfo(newXmlPath));
  100. if (cfg != null)
  101. {
  102. foreach (WagoDeviceConfig config in cfg.WagoDeviceConfigs)
  103. {
  104. if (port == config.Port)
  105. {
  106. //加载DO
  107. int i = 0;
  108. DONameIndexDic = new Dictionary<string, int>();
  109. foreach (var group in config.WagoDigOut.WagoDOGroups)
  110. {
  111. foreach (var item in group.WagoDOs)
  112. {
  113. DONameIndexDic[item.Name] = i;
  114. }
  115. }
  116. //加载DI
  117. i = 0;
  118. DINameIndexDic = new Dictionary<string, int>();
  119. foreach (var group in config.WagoDigIn.WagoDIGroups)
  120. {
  121. foreach(var item in group.WagoDIs)
  122. {
  123. DINameIndexDic[item.Name] = i;
  124. i++;
  125. }
  126. }
  127. //加载AO
  128. i = 0;
  129. AONameIndexDic = new Dictionary<string, int>();
  130. foreach (var group in config.WagoAnoOut.WagoAOGroups)
  131. {
  132. foreach (var item in group.WagoAOs)
  133. {
  134. AONameIndexDic[item.Name] = i;
  135. i++;
  136. }
  137. }
  138. //加载AI
  139. i = 0;
  140. AINameIndexDic = new Dictionary<string, int>();
  141. foreach (var group in config.WagoAnoIn.WagoAIGroups)
  142. {
  143. foreach (var item in group.WagoAIs)
  144. {
  145. AINameIndexDic[item.Name] = i;
  146. i++;
  147. }
  148. }
  149. }
  150. }
  151. }
  152. }
  153. catch
  154. {
  155. LOG.WriteLog(eEvent.ERR_WAGO, "Wago", "Load wago WagoControllerCfg-Simulator.xml failed");
  156. }
  157. //设置IO变量默认值
  158. if (AINameIndexDic.ContainsKey("r_LoaderA_LS_Vacuum_anlg")) AIShorts[AINameIndexDic["r_LoaderA_LS_Vacuum_anlg"]] = 0x32C8;
  159. if (AINameIndexDic.ContainsKey("r_LoaderB_LS_Vacuum_anlg")) AIShorts[AINameIndexDic["r_LoaderB_LS_Vacuum_anlg"]] = 0x32C8;
  160. if (AINameIndexDic.ContainsKey("r_DPUF_A_CHUCK_A_VAC")) AIShorts[AINameIndexDic["r_DPUF_A_CHUCK_A_VAC"]] = 0x32C8;
  161. if (AINameIndexDic.ContainsKey("r_DPUF_A_CHUCK_B_VAC")) AIShorts[AINameIndexDic["r_DPUF_A_CHUCK_B_VAC"]] = 0x32C8;
  162. }
  163. #region 公共方法
  164. public void UpdataDOBytes(string name,int value)
  165. {
  166. if (DONameIndexDic.ContainsKey(name))
  167. {
  168. if (DONameIndexDic[name] < DOBytes.Length)
  169. {
  170. DOBytes[DONameIndexDic[name]] = value == 0 ? (byte)0 : (byte)1;
  171. }
  172. }
  173. }
  174. public void UpdataDIBytes(string name, int value)
  175. {
  176. if (DINameIndexDic.ContainsKey(name))
  177. {
  178. if (DINameIndexDic[name] < DIBytes.Length)
  179. {
  180. DIBytes[DINameIndexDic[name]] = value == 0 ? (byte)0 : (byte)1;
  181. }
  182. }
  183. }
  184. public void UpdataAOShorts(string name, int value)
  185. {
  186. if (AONameIndexDic.ContainsKey(name))
  187. {
  188. string hexValue = value.ToString("X2");
  189. try
  190. {
  191. short result = Convert.ToInt16(hexValue, 16);
  192. if (AONameIndexDic[name] < AOShorts.Length)
  193. {
  194. AOShorts[AONameIndexDic[name]] = result;
  195. }
  196. }
  197. catch (FormatException)
  198. {
  199. }
  200. }
  201. }
  202. public void UpdataAIShorts(string name, int value)
  203. {
  204. if (AINameIndexDic.ContainsKey(name))
  205. {
  206. string hexValue = value.ToString("X2");
  207. try
  208. {
  209. short result = Convert.ToInt16(hexValue, 16);
  210. if(AINameIndexDic[name] < AIShorts.Length)
  211. {
  212. AIShorts[AINameIndexDic[name]] = result;
  213. }
  214. }
  215. catch (FormatException)
  216. {
  217. }
  218. }
  219. }
  220. #endregion
  221. #region 功能方法
  222. /// <summary>
  223. /// 将长度为8的二进制byte数组转成对应十六进制byte值(大端模式)
  224. /// </summary>
  225. /// <param name="byteArray"></param>
  226. /// <returns></returns>
  227. public byte ConvertByteArrayToHex(byte[] byteArray)
  228. {
  229. byte result = 0;
  230. // 先将 byte 数组转换为二进制数
  231. int binaryValue = 0;
  232. for (int i = 0; i < 8; i++)
  233. {
  234. binaryValue |= (byteArray[i] << (7 - i));
  235. }
  236. // 逆转二进制数
  237. int reversedValue = 0;
  238. for (int i = 0; i < 8; i++)
  239. {
  240. reversedValue |= ((binaryValue >> i) & 1) << (7 - i);
  241. }
  242. // 转换为十六进制byte
  243. if (byte.TryParse(reversedValue.ToString("X2"), System.Globalization.NumberStyles.HexNumber, null, out result))
  244. {
  245. return result;
  246. }
  247. return 0;
  248. }
  249. /// <summary>
  250. /// 将short数组转成长度两倍的byte数组
  251. /// </summary>
  252. /// <param name="shortArray"></param>
  253. /// <returns></returns>
  254. private byte[] ConvertShortArrayToByteArray(short[] shortArray)
  255. {
  256. byte[] byteArray = new byte[shortArray.Length * 2];
  257. for (int i = 0; i < shortArray.Length; i++)
  258. {
  259. byte[] tempBytes = BitConverter.GetBytes(shortArray[i]);
  260. Array.Reverse(tempBytes);
  261. Array.Copy(tempBytes, 0, byteArray, i * 2, 2);
  262. }
  263. return byteArray;
  264. }
  265. #endregion
  266. protected override void ProcessUnsplitMessage(byte[] data)
  267. {
  268. byte command = data[7];
  269. if (command == 0x01) //读DO
  270. {
  271. short flag = byteTransform.TransInt16(data, 0);
  272. byte channel = data[6];
  273. short startAddress = byteTransform.TransInt16(data, 8);
  274. short bitCount = byteTransform.TransInt16(data, 10);
  275. byte byteCount = (byte)(bitCount / 8 + 1);
  276. byte[] bytes = new byte[byteCount];
  277. for(int i = 0; i < byteCount;i++)
  278. {
  279. byte[] tempbytes = new byte[8];
  280. Array.Copy(DOBytes,8 * i, tempbytes, 0, 8);
  281. bytes[i] = ConvertByteArrayToHex(tempbytes);
  282. }
  283. OnWriteMessage(CreateReadDigitalResponse(flag, channel, command, byteCount, bytes));
  284. return;
  285. }
  286. else if(command == 0x03)//读AO
  287. {
  288. short flag = byteTransform.TransInt16(data, 0);
  289. byte channel = data[6];
  290. short startAddress = byteTransform.TransInt16(data, 8);
  291. short registerCount = byteTransform.TransInt16(data, 10);
  292. short[] shorts = new short[registerCount];//获取指定寄存器里的内容
  293. Array.Copy(AOShorts, 0, shorts, 0, registerCount);
  294. byte[] bytes = new byte[registerCount * 2];
  295. bytes = ConvertShortArrayToByteArray(shorts); //转入长度为shorts数组长度两倍的bytes数组中
  296. OnWriteMessage(CreateReadAnalogyResponse(flag, channel, command, (byte)registerCount, bytes));
  297. return;
  298. }
  299. else if (command == 0x02)//读DI
  300. {
  301. short flag = byteTransform.TransInt16(data, 0);
  302. byte channel = data[6];
  303. short startAddress = byteTransform.TransInt16(data, 8);
  304. short bitCount = byteTransform.TransInt16(data, 10);
  305. byte byteCount = (byte)(bitCount / 8 + 1);
  306. byte[] bytes = new byte[byteCount];
  307. for (int i = 0; i < byteCount; i++)
  308. {
  309. byte[] tempbytes = new byte[8];
  310. Array.Copy(DIBytes, 8 * i, tempbytes, 0, 8);
  311. bytes[i] = ConvertByteArrayToHex(tempbytes);
  312. }
  313. OnWriteMessage(CreateReadDigitalResponse(flag, channel, command, byteCount, bytes));
  314. return;
  315. }
  316. else if (command == 0x04)//读AI
  317. {
  318. short flag = byteTransform.TransInt16(data, 0);
  319. byte channel = data[6];
  320. short startAddress = byteTransform.TransInt16(data, 8);
  321. short registerCount = byteTransform.TransInt16(data, 10);
  322. short[] shorts = new short[registerCount];//获取指定寄存器里的内容
  323. Array.Copy(AIShorts, 0, shorts, 0, registerCount);
  324. byte[] bytes = new byte[registerCount * 2];
  325. bytes = ConvertShortArrayToByteArray(shorts); //转入长度为shorts数组两倍的bytes数组中
  326. OnWriteMessage(CreateReadAnalogyResponse(flag, channel, command, (byte)registerCount, bytes));
  327. return;
  328. }
  329. else if (command == 0x05)//写DO
  330. {
  331. short startAddress = byteTransform.TransInt16(data, 8);
  332. if (startAddress > 0x03FF || startAddress < WRITE_DO_STARTADDRESS)
  333. {
  334. short flag = byteTransform.TransInt16(data, 0);
  335. byte channel = data[6];
  336. OnWriteMessage(CreateError(flag, channel, command, 0x02)); //地址错误
  337. return;
  338. }
  339. int position = startAddress - WRITE_DO_STARTADDRESS;
  340. bool status = data[10] == 0xFF ? true : false;
  341. lock (_writeDOLocker)
  342. {
  343. DOBytes[position] = status ? (byte)1 : (byte)0;
  344. }
  345. OnWriteMessage(data); //原消息返回
  346. //触发Wago对应数据更新
  347. UpdateDataCausedByWago(position, status);
  348. return;
  349. }
  350. else if (command == 0x06)//写AO
  351. {
  352. short startAddress = byteTransform.TransInt16(data, 8);
  353. if(startAddress > 0x02FF || startAddress < WRITE_AO_STARTADDRESS)
  354. {
  355. short flag = byteTransform.TransInt16(data, 0);
  356. byte channel = data[6];
  357. OnWriteMessage(CreateError(flag, channel, command, 0x02)); //地址错误
  358. return;
  359. }
  360. int position = startAddress - WRITE_AO_STARTADDRESS;
  361. short value = byteTransform.TransInt16(data, 10);
  362. lock (_writeAOLocker)
  363. {
  364. AOShorts[position] = value;
  365. }
  366. OnWriteMessage(data); //原消息返回
  367. return;
  368. }
  369. else
  370. {
  371. short flag = byteTransform.TransInt16(data, 0);
  372. byte channel = data[6];
  373. OnWriteMessage(CreateError(flag, channel, command, 0x01)); //指令错误
  374. return;
  375. }
  376. }
  377. /// <summary>
  378. /// 回复读数字量
  379. /// </summary>
  380. /// <param name="flag"></param>
  381. /// <param name="channel"></param>
  382. /// <param name="command"></param>
  383. /// <param name="byteCount"></param>
  384. /// <param name="values"></param>
  385. /// <returns></returns>
  386. private byte[] CreateReadDigitalResponse(short flag, byte channel, byte command, byte byteCount, byte[] values)
  387. {
  388. byte[] bytes = new byte[7 + 2 + values.Length]; //回复字节长度,前面7个字节固定长度 + functionCode一个字节 + byteCount一个字节+values.length个字节
  389. Array.Copy(byteTransform.GetBytes(flag), 0, bytes, 0, 2);
  390. bytes[2] = 0x00;
  391. bytes[3] = 0x00;
  392. short dataLength = (short)(3 + values.Length);
  393. Array.Copy(byteTransform.GetBytes(dataLength), 0, bytes, 4, 2);
  394. bytes[6] = channel;
  395. bytes[7] = command;
  396. bytes[8] = byteCount;
  397. Array.Copy(values, 0, bytes, 9, values.Length);
  398. return bytes;
  399. }
  400. /// <summary>
  401. /// 回复读模拟量
  402. /// </summary>
  403. /// <param name="flag"></param>
  404. /// <param name="channel"></param>
  405. /// <param name="command"></param>
  406. /// <param name="registerCount"></param>
  407. /// <param name="values"></param>
  408. /// <returns></returns>
  409. private byte[] CreateReadAnalogyResponse(short flag, byte channel, byte command, byte registerCount, byte[] values)
  410. {
  411. byte[] bytes = new byte[7 + 2 + 2 * registerCount]; //回复字节长度,前面7个字节固定长度 + functionCode一个字节 + byteCount一个字节+registerCount*2个字节(一个寄存器占两个字节)
  412. Array.Copy(byteTransform.GetBytes(flag), 0, bytes, 0, 2);
  413. bytes[2] = 0x00;
  414. bytes[3] = 0x00;
  415. short dataLength = (short)(3 + 2 * registerCount);
  416. Array.Copy(byteTransform.GetBytes(dataLength), 0, bytes, 4, 2);
  417. bytes[6] = channel;
  418. bytes[7] = command;
  419. bytes[8] = (byte)(2 * registerCount);
  420. Array.Copy(values, 0, bytes, 9, values.Length);
  421. return bytes;
  422. }
  423. /// <summary>
  424. /// 错误回复
  425. /// </summary>
  426. /// <param name="flag"></param>
  427. /// <param name="channel"></param>
  428. /// <param name="command"></param>
  429. /// <param name="error"></param>
  430. /// <returns></returns>
  431. private byte[] CreateError(short flag, byte channel, byte command, byte error)
  432. {
  433. byte[] bytes = new byte[9];
  434. Array.Copy(byteTransform.GetBytes(flag), 0, bytes, 0, 2);
  435. bytes[2] = 0x00;
  436. bytes[3] = 0x00;
  437. bytes[4] = 0x00;
  438. bytes[5] = 0x03;
  439. bytes[6] = channel;
  440. bytes[7] = (byte)(command | 0x80);
  441. bytes[8] = error;
  442. return bytes;
  443. }
  444. }
  445. }