FestoSocketSimulator.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. using Aitex.Common.Util;
  2. using Aitex.Core.RT.Device;
  3. using Aitex.Core.RT.IOCore;
  4. using Aitex.Core.Util;
  5. using MECF.Framework.Common.Device.Festo;
  6. using MECF.Framework.Common.Net;
  7. using MECF.Framework.Simulator.Core.Driver;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.IO;
  11. using System.Net;
  12. using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
  13. namespace CyberX8_Simulator.Devices
  14. {
  15. public class FestoSocketSimulator : SocketDeviceSimulator
  16. {
  17. //Write Address
  18. private const ushort FESTO_DO_START_ADDRESS = 0x9C43;//FestoDO起始地址(40003)
  19. //Read Address
  20. private const ushort FESTO_DI_START_ADDRESS = 0xB153;//FestoDI起始地址(45395)
  21. //Register Count
  22. private const int FESTO_REGISTER_COUNT = 100;
  23. private IByteTransform byteTransform = new BigEndianByteTransformBase();
  24. /// <summary>
  25. /// 数据(index - data)
  26. /// </summary>
  27. private short[] _festoOutputDataDic = new short[FESTO_REGISTER_COUNT];
  28. /// <summary>
  29. /// 数据(DOName - index)
  30. /// </summary>
  31. private Dictionary<string, FestoDO> _festoNameIndexDic = new Dictionary<string, FestoDO>();
  32. /// <summary>
  33. /// do 索引对象字典(key-地址索引-bit,value--do名称)
  34. /// </summary>
  35. private Dictionary<string, string> _doNameDictionary = new Dictionary<string, string>();
  36. /// <summary>
  37. /// 构造函数
  38. /// </summary>
  39. /// <param name="port"></param>
  40. public FestoSocketSimulator(int port) : base(port)
  41. {
  42. for(int i = 0; i < FESTO_REGISTER_COUNT; i++)
  43. {
  44. _festoOutputDataDic[i] = 0x00;
  45. }
  46. string oldXmlPath = PathManager.GetCfgDir();
  47. string newXmlPath = oldXmlPath.Replace("CyberX8_Simulator", "CyberX8_RT") + "Devices\\FestoControllerCfg-Simulator.xml";
  48. FestoControllerCfg cfg = CustomXmlSerializer.Deserialize<FestoControllerCfg>(new FileInfo(newXmlPath));
  49. foreach (FestoDeviceConfig config in cfg.FestoDeviceConfigs)
  50. {
  51. if(port == config.Port)
  52. {
  53. foreach (FestoDO item in config.FestoDoes)
  54. {
  55. _festoNameIndexDic[item.Name] = item;
  56. string str = $"{item.Address}-{item.Bit}";
  57. _doNameDictionary[str] = item.Name;
  58. }
  59. }
  60. }
  61. }
  62. /// <summary>
  63. /// 解析信息
  64. /// </summary>
  65. /// <param name="data"></param>
  66. protected override void ProcessUnsplitMessage(byte[] data)
  67. {
  68. short flag = byteTransform.TransInt16(data, 0);//事务标识符
  69. byte channel = data[6];//单元标识符
  70. byte command = data[7];//功能码
  71. if (command == 0x03)//读取
  72. {
  73. ushort startAddress = byteTransform.TransUInt16(data, 8);//起始寄存器地址
  74. short registerCount = byteTransform.TransInt16(data, 10);//寄存器数量
  75. byte[] bytes = new byte[2 * registerCount];//读取2*registerCount Byte数据
  76. if (startAddress >= FESTO_DI_START_ADDRESS)
  77. {
  78. for (int i = 0; i < registerCount; i++)
  79. {
  80. Array.Copy(byteTransform.GetBytes(_festoOutputDataDic[startAddress - FESTO_DI_START_ADDRESS + i]), 0, bytes, i * 2, 2);
  81. }
  82. OnWriteMessage(CreateReadResponse(flag, channel, command, registerCount, bytes));
  83. }
  84. else
  85. {
  86. OnWriteMessage(CreateError(flag, channel, command, 0x8A));
  87. }
  88. }
  89. else if(command == 0x06)//写入
  90. {
  91. ushort startAddress = byteTransform.TransUInt16(data, 8);//起始寄存器地址
  92. short value = byteTransform.TransInt16(data, 10);//写入的值(2 Byte)
  93. if(startAddress >= FESTO_DO_START_ADDRESS)
  94. {
  95. //通知相关数据变化
  96. var result = DecodeDOData(startAddress, value);
  97. SimulatorCommManager.Instance.CheckDataChanged(result.Item1, result.Item2);
  98. //modbus起始地址n为数据,n+1为诊断数据,取地址n下的数据
  99. _festoOutputDataDic[(startAddress - FESTO_DO_START_ADDRESS) * 2] = value;
  100. OnWriteMessage(CreateWriteResponse(flag, channel, command, startAddress, value));
  101. }
  102. else
  103. {
  104. OnWriteMessage(CreateError(flag, channel, command, 0x8A));
  105. }
  106. }
  107. else
  108. {
  109. OnWriteMessage(CreateError(flag, channel, command, 0x84));
  110. }
  111. }
  112. /// <summary>
  113. /// 读回复
  114. /// </summary>
  115. /// <param name="flag"></param>
  116. /// <param name="channel"></param>
  117. /// <param name="command"></param>
  118. /// <param name="registerCount"></param>
  119. /// <param name="values"></param>
  120. /// <returns></returns>
  121. private byte[] CreateReadResponse(short flag, byte channel, byte command, short registerCount, byte[] values)
  122. {
  123. byte[] bytes = new byte[6 + 3 + values.Length];
  124. Array.Copy(byteTransform.GetBytes(flag), 0, bytes, 0, 2);
  125. bytes[2] = 0x00;
  126. bytes[3] = 0x00;
  127. short dataLength = (short)(3 + values.Length);
  128. Array.Copy(byteTransform.GetBytes(dataLength), 0, bytes, 4, 2);
  129. bytes[6] = channel;
  130. bytes[7] = command;
  131. bytes[8] = (byte)(2 * registerCount);
  132. Array.Copy(values, 0, bytes, 9, values.Length);
  133. return bytes;
  134. }
  135. /// <summary>
  136. /// 写回复
  137. /// </summary>
  138. /// <param name="flag"></param>
  139. /// <param name="channel"></param>
  140. /// <param name="command"></param>
  141. /// <param name="startAddress"></param>
  142. /// <param name="value"></param>
  143. /// <returns></returns>
  144. private byte[] CreateWriteResponse(short flag, byte channel, byte command, ushort startAddress, short value)
  145. {
  146. byte[] bytes = new byte[12];
  147. Array.Copy(byteTransform.GetBytes(flag), 0, bytes, 0, 2);
  148. bytes[2] = 0x00;
  149. bytes[3] = 0x00;
  150. bytes[4] = 0x00;
  151. bytes[5] = 0x06;
  152. bytes[6] = channel;
  153. bytes[7] = command;
  154. byte[] addressByt = byteTransform.GetBytes(startAddress);
  155. Array.Copy(addressByt, 0, bytes, 8, 2);
  156. byte[] valueByt = byteTransform.GetBytes(value);
  157. Array.Copy(valueByt, 0, bytes, 10, 2);
  158. return bytes;
  159. }
  160. /// <summary>
  161. /// 错误回复
  162. /// </summary>
  163. /// <param name="flag"></param>
  164. /// <param name="channel"></param>
  165. /// <param name="command"></param>
  166. /// <param name="error"></param>
  167. /// <returns></returns>
  168. private byte[] CreateError(short flag, byte channel, byte command, byte error)
  169. {
  170. byte[] bytes = new byte[9];
  171. Array.Copy(byteTransform.GetBytes(flag), 0, bytes, 0, 2);
  172. bytes[2] = 0x00;
  173. bytes[3] = 0x00;
  174. bytes[4] = 0x00;
  175. bytes[5] = 0x03;
  176. bytes[6] = channel;
  177. bytes[7] = (byte)(command | 0x80);
  178. bytes[8] = error;
  179. return bytes;
  180. }
  181. /// <summary>
  182. /// 更新DI数据
  183. /// </summary>
  184. /// <param name="name"></param>
  185. /// <param name="value"></param>
  186. public void UpdataDOBytes(string name, int value)
  187. {
  188. if (_festoNameIndexDic.ContainsKey(name))
  189. {
  190. FestoDO festoDO = _festoNameIndexDic[name];
  191. short byteValue = (short) (_festoOutputDataDic[(festoDO.Address - FESTO_DO_START_ADDRESS) * 2] & ~(1 << festoDO.Bit));
  192. short tmp = (short)(value << festoDO.Bit);
  193. _festoOutputDataDic[(festoDO.Address - FESTO_DO_START_ADDRESS) * 2] = (short)(byteValue | tmp);
  194. }
  195. }
  196. /// <summary>
  197. /// 解析数据
  198. /// </summary>
  199. /// <param name="address"></param>
  200. /// <param name="value"></param>
  201. /// <returns></returns>
  202. private (string, bool) DecodeDOData(ushort address, short value)
  203. {
  204. int index = (address - FESTO_DO_START_ADDRESS) * 2;
  205. int bitNum = (int)Math.Log(_festoOutputDataDic[index] ^ value, 2);
  206. bool valueBool = (value & (1 << bitNum)) != 0 ? true : false;
  207. string str = $"{address}-{bitNum}";
  208. return (_doNameDictionary[str], valueBool);
  209. }
  210. }
  211. }