ModbusTcp.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. using System;
  2. using System.Timers;
  3. using System.Collections.Generic;
  4. using Newtonsoft.Json.Linq;
  5. using ProjectBase.Data.Logs;
  6. using ProjectBase.Data.Redis;
  7. using ProjectBase.Data.BaseDAL;
  8. using Modbus.Device;
  9. using SIMDP.Model;
  10. using ProjectBase.Util;
  11. using SIMDP.BLL;
  12. using System.Linq;
  13. using System.Reflection;
  14. using System.Net.Sockets;
  15. namespace SIMDP.Device
  16. {
  17. public class ModbusTcp : AbstractBaseDevice
  18. {
  19. #region 数据定义
  20. /// <summary>
  21. /// ModbusTcp配置信息
  22. /// </summary>
  23. protected ModbusTcpConfig config;
  24. /// <summary>
  25. /// Modbus对象
  26. /// </summary>
  27. protected IModbusMaster master;
  28. /// <summary>
  29. /// TCP连接对象
  30. /// </summary>
  31. protected TcpClient tcpClient;
  32. /// <summary>
  33. /// 数据节点字典 key-变量名称, value-节点信息
  34. /// </summary>
  35. protected Dictionary<string, ModbusDataPointInfo> allPoints = new Dictionary<string, ModbusDataPointInfo>();
  36. /// <summary>
  37. /// 监控节点列表
  38. /// </summary>
  39. protected List<ModbusDataPointInfo> monitorPoints = new List<ModbusDataPointInfo>();
  40. /// <summary>
  41. /// 连接状态
  42. /// </summary>
  43. protected bool isConnect = false;
  44. #endregion
  45. #region TYPE定义
  46. public class ModbusTcpConfig
  47. {
  48. public ModbusTcpConfig(string json)
  49. {
  50. JObject jObject = JObject.Parse(json);
  51. JToken token;
  52. if ((token = jObject["IP"]) != null)
  53. IP = (string)token;
  54. if ((token = jObject["PORT"]) != null)
  55. PORT = (int)token;
  56. if ((token = jObject["TIMER"]) != null)
  57. TIMER = (double)token;
  58. }
  59. // 串口属性
  60. public string IP { get; set; } = "127.0.0.1";
  61. public int PORT { get; set; } = 502;
  62. // 轮询时间
  63. public double TIMER { get; set; } = 200;
  64. }
  65. public class ModbusDataPointInfo
  66. {
  67. // 节点配置信息
  68. public MoDataPoint mo;
  69. // 节点属性
  70. public string 类型 { get; set; }
  71. public byte 站号 { get; set; }
  72. public ushort 地址 { get; set; }
  73. public ushort 长度 { get; set; } = 1;
  74. // 节点值及动作定义
  75. public object value = null;
  76. public MethodInfo proc = null;
  77. public ModbusDataPointInfo(MoDataPoint _mo)
  78. {
  79. mo = _mo;
  80. 类型 = SysEnvironment.dirType.FirstOrDefault(p => p.Key == mo.DataPointType).Value;
  81. JObject jObject = JObject.Parse(mo.DataPointSource);
  82. 站号 = Convert.ToByte((string)jObject["站号"]);
  83. 地址 = Convert.ToUInt16((string)jObject["地址"]);
  84. if (jObject["长度"] != null)
  85. 长度 = Convert.ToUInt16((string)jObject["长度"]);
  86. }
  87. }
  88. #endregion
  89. #region 接口实现
  90. public override void Start(MoPlcInfo _plcInfo, List<MoDataPoint> _dataPoints)
  91. {
  92. plcInfo = _plcInfo;
  93. config = new ModbusTcpConfig(plcInfo.LinkConfig);
  94. timer.Interval = config.TIMER;
  95. timer.Elapsed += timer_Elapsed;
  96. timer.AutoReset = false;
  97. // PLC未连接状态
  98. SetRedisPlcDisConnect();
  99. // 创建PLC数据点表
  100. CreateDataPointList(_dataPoints);
  101. // 初始化自定义函数
  102. actionStart();
  103. // 启动时尝试连接一次设备
  104. Connect();
  105. // 启动定时器
  106. timerStopped = false;
  107. timer.Start();
  108. }
  109. /// <summary>
  110. /// PLC连接状态
  111. /// </summary>
  112. public override bool isConnected()
  113. {
  114. return isConnect;
  115. }
  116. protected override bool Connect()
  117. {
  118. tcpClient = new TcpClient
  119. {
  120. ReceiveTimeout = 1000
  121. };
  122. tcpClient.Connect(config.IP, config.PORT);
  123. master = ModbusIpMaster.CreateIp(tcpClient);
  124. SetRedisPlcConnected();
  125. LogHelper.log.Info("已连接到Modbus TCP: " + config.IP);
  126. isConnect = true;
  127. actionConnected();
  128. return isConnected();
  129. }
  130. protected override void Disconnect()
  131. {
  132. if (tcpClient != null)
  133. tcpClient.Close();
  134. isConnect = false;
  135. if (master != null)
  136. master.Dispose();
  137. SetRedisPlcDisConnect();
  138. }
  139. protected void CreateDataPointList(List<MoDataPoint> dataPoints)
  140. {
  141. if (redis == null)
  142. redis = new RedisHelper();
  143. Type t = this.GetType();
  144. foreach (MoDataPoint dataPoint in dataPoints)
  145. {
  146. ModbusDataPointInfo dataPointInfo = new ModbusDataPointInfo(dataPoint);
  147. allPoints.Add(dataPoint.DataPointName, dataPointInfo);
  148. redis.SetString(dataPoint.DataPointId.ToString() + dataPoint.DataPointName, "");
  149. //if (BLLFactory<BlDataGroup>.Instance.IsSignalGroupById(dataPoint.DataPointGroupId))
  150. // 不再按照信号组类型区分是否为监控节点,只按照是否有执行逻辑
  151. if (dataPoint.DataProc.Trim() != "")
  152. {
  153. dataPointInfo.proc = t.GetMethod(dataPoint.DataProc);
  154. monitorPoints.Add(dataPointInfo);
  155. }
  156. }
  157. }
  158. #endregion
  159. #region 读写操作
  160. /// <summary>
  161. /// 读取寄存器数据
  162. /// </summary>
  163. public bool Read(string dataPointName, out object value)
  164. {
  165. value = null;
  166. if (!allPoints.ContainsKey(dataPointName))
  167. {
  168. return false;
  169. }
  170. ModbusDataPointInfo pointInfo = allPoints[dataPointName];
  171. return Read(pointInfo, out value);
  172. }
  173. public bool Read(ModbusDataPointInfo pointInfo, out object value)
  174. {
  175. bool[] coilsBuffer; //线圈数组
  176. ushort[] registerBuffer; // 寄存器数组
  177. value = (Decimal)0;
  178. string binary = "";
  179. try
  180. {
  181. if (pointInfo.类型 == "BOOL")
  182. {
  183. coilsBuffer = master.ReadCoils(pointInfo.站号, pointInfo.地址, pointInfo.长度);
  184. for (int i = 0; i < coilsBuffer.Length; i++)
  185. {
  186. value = (Decimal)value * 2 + (coilsBuffer[i] ? 1 : 0);
  187. binary += coilsBuffer[i] ? "1" : "0";
  188. }
  189. UpdataRedisDataPoint(pointInfo.mo, binary);
  190. }
  191. else
  192. {
  193. registerBuffer = master.ReadHoldingRegisters(pointInfo.站号, pointInfo.地址, pointInfo.长度);
  194. for (int i = 0; i < registerBuffer.Length; i++)
  195. {
  196. value = (Decimal)value * 256 + registerBuffer[i];
  197. }
  198. UpdataRedisDataPoint(pointInfo.mo, value.ToString());
  199. }
  200. return true;
  201. }
  202. catch (Exception ex)
  203. {
  204. LogHelper.log.Error("读取Modbus(" + config.IP + ")信号(" + pointInfo.mo.DataPointName + ")发生异常:" + ex.Message);
  205. Disconnect();
  206. return false;
  207. }
  208. }
  209. #endregion
  210. }
  211. }