FestoSocketSimulator.cs 9.8 KB

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