ModbusRtu.cs 7.7 KB

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