You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

427 lines
14 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Net.Sockets;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using NModbus;
  8. using HBLConsole.Service;
  9. using System.Threading;
  10. using HBLConsole.Model;
  11. namespace HBLConsole.Communication
  12. {
  13. public class ModbusTcpHelper
  14. {
  15. private volatile static ModbusTcpHelper _Instance;
  16. public static ModbusTcpHelper GetInstance => _Instance ?? (_Instance = new ModbusTcpHelper());
  17. private ModbusTcpHelper() { }
  18. private ModbusFactory modbusFactory;
  19. private IModbusMaster master;
  20. private TcpClient tcpClient;
  21. private string IPAdress;
  22. private int Port;
  23. //public Action ConnectOk { get; set; }
  24. /// <summary>
  25. /// 判断是否连接成功
  26. /// </summary>
  27. public bool Connected => tcpClient == null ? false : tcpClient.Connected;
  28. /// <summary>
  29. /// ModbusTcp 连接设备
  30. /// </summary>
  31. /// <param name="ip">ip 地址</param>
  32. /// <param name="port">端口号,默认502</param>
  33. public void ModbusTcpConnect(string ip, int port = 502)
  34. {
  35. MessageLog.GetInstance.Show($"设备【{ip}:{port}】连接中。。。。");
  36. IPAdress = ip;
  37. Port = port;
  38. modbusFactory = new ModbusFactory();
  39. Connect();
  40. master.Transport.ReadTimeout = 2000;//读取超时时间
  41. master.Transport.WriteTimeout = 2000;//写入超时时间
  42. master.Transport.Retries = 10;//重试次数
  43. ActionOperate.GetInstance.Send("ConnectOk");
  44. MessageLog.GetInstance.Show($"设备【{ip}:{port}】连接成功");
  45. }
  46. private void Connect()
  47. {
  48. bool ErrorFlag = false;
  49. while (!Connected)
  50. {
  51. try
  52. {
  53. tcpClient = new TcpClient(IPAdress, Port);
  54. master = modbusFactory.CreateMaster(tcpClient);
  55. }
  56. catch (Exception ex)
  57. {
  58. if (!ErrorFlag)
  59. {
  60. MessageLog.GetInstance.Show($"ModbusTcp 连接失败,IP = {IPAdress},Port = {Port}");
  61. MessageLog.GetInstance.Show(ex.ToString());
  62. ErrorFlag = true;
  63. }
  64. Thread.Sleep(3000);
  65. }
  66. }
  67. MessageLog.GetInstance.Show("ModbusTcp 连接成功!");
  68. }
  69. public void Readbool(ushort startAddress, ushort len, Action<bool[]> action)
  70. {
  71. object result;
  72. result = Read(startAddress, ReadType.Coils, len);
  73. if (result != null)
  74. {
  75. if (result is bool[] bools)
  76. {
  77. if (bools.Length == len)
  78. {
  79. action(bools);
  80. }
  81. }
  82. }
  83. }
  84. public object Read(ushort startAddress, ReadType readType, ushort num = 1, byte slaveAddress = 1)
  85. {
  86. object result = new object();
  87. if (tcpClient == null) return result;
  88. if (num <= 0) return result;
  89. try
  90. {
  91. switch (readType)
  92. {
  93. case ReadType.Coils:
  94. result = master.ReadCoils(slaveAddress, startAddress, num);
  95. break;
  96. case ReadType.Inputs:
  97. result = master.ReadInputs(slaveAddress, startAddress, num);
  98. break;
  99. case ReadType.HoldingRegisters:
  100. result = master.ReadHoldingRegisters(slaveAddress, startAddress, num);
  101. break;
  102. case ReadType.InputRegisters:
  103. result = master.ReadInputRegisters(slaveAddress, startAddress, num);
  104. break;
  105. default:
  106. break;
  107. }
  108. if (result == null) return new object();
  109. if (result is bool[] bools)
  110. {
  111. if (bools.Length == 1)
  112. return bools[0];
  113. else
  114. return bools;
  115. }
  116. if (result is ushort[] ushorts)
  117. {
  118. if (ushorts.Length == 1)
  119. return ushorts[0];
  120. else
  121. return ushorts;
  122. }
  123. }
  124. catch (Exception ex)
  125. {
  126. MessageLog.GetInstance.Show(ex.ToString());
  127. if (ex.InnerException is SocketException)
  128. {
  129. tcpClient = null;
  130. Connect();
  131. }
  132. }
  133. return result;
  134. }
  135. public bool Write(ushort startAddress, WriteType writeType, object InputValue, byte slaveAddress = 1)
  136. {
  137. bool result = false;
  138. if (tcpClient == null) return result;
  139. if (!(InputValue is bool || InputValue is bool[] || InputValue is ushort || InputValue is ushort[])) return result;
  140. try
  141. {
  142. switch (writeType)
  143. {
  144. case WriteType.Coils:
  145. if (InputValue is bool boolValue)
  146. master.WriteSingleCoil(slaveAddress, startAddress, boolValue);
  147. if (InputValue is bool[] boolsValue)
  148. master.WriteMultipleCoils(slaveAddress, startAddress, boolsValue);
  149. break;
  150. case WriteType.HoldingRegisters:
  151. if (InputValue is ushort ushortValue)
  152. master.WriteSingleRegister(slaveAddress, startAddress, ushortValue);
  153. if (InputValue is ushort[] ushortsValue)
  154. {
  155. int len = 100;
  156. if (ushortsValue.Length > len)
  157. {
  158. List<ushort[]> ushortLists = new List<ushort[]>();
  159. for (int i = 0; i < ushortsValue.Length / len; i++)
  160. {
  161. ushortLists.Add(ushortsValue.Skip(0).Take(len).ToArray());
  162. }
  163. int y = ushortsValue.Length % len;
  164. if (y > 0)
  165. {
  166. ushortLists.Add(ushortsValue.Skip(ushortsValue.Length - y).Take(y).ToArray());
  167. }
  168. foreach (var item in ushortLists)
  169. {
  170. master.WriteMultipleRegisters(slaveAddress, startAddress, item);
  171. startAddress += (ushort)item.Length;
  172. }
  173. }
  174. else
  175. {
  176. master.WriteMultipleRegisters(slaveAddress, startAddress, ushortsValue);
  177. }
  178. }
  179. break;
  180. default:
  181. break;
  182. }
  183. }
  184. catch (Exception ex)
  185. {
  186. MessageLog.GetInstance.Show(ex.ToString());
  187. if (ex.InnerException is SocketException)
  188. {
  189. tcpClient = null;
  190. Connect();
  191. }
  192. return false;
  193. }
  194. return true;
  195. }
  196. #region 批量数据读取
  197. /// <summary>
  198. /// 读取多个线圈
  199. /// </summary>
  200. /// <param name="startAddress"></param>
  201. /// <param name="num"></param>
  202. /// <param name="slaveAddress"></param>
  203. /// <returns></returns>
  204. public bool[] ReadCoils(ushort startAddress, ushort num, byte slaveAddress = 1)
  205. {
  206. return master.ReadCoils(slaveAddress, startAddress, num);
  207. }
  208. /// <summary>
  209. /// 读取多个输入线圈
  210. /// </summary>
  211. /// <param name="startAddress"></param>
  212. /// <param name="num"></param>
  213. /// <param name="slaveAddress"></param>
  214. /// <returns></returns>
  215. public bool[] ReadInputs(ushort startAddress, ushort num, byte slaveAddress = 1)
  216. {
  217. return master.ReadInputs(slaveAddress, startAddress, num);
  218. }
  219. /// <summary>
  220. /// 读取多个保持寄存器
  221. /// </summary>
  222. /// <param name="startAddress"></param>
  223. /// <param name="num"></param>
  224. /// <param name="slaveAddress"></param>
  225. /// <returns></returns>
  226. public ushort[] ReadHoldingRegisters(ushort startAddress, ushort num, byte slaveAddress = 1)
  227. {
  228. return master.ReadHoldingRegisters(slaveAddress, startAddress, num);
  229. }
  230. /// <summary>
  231. /// 读取多个输入寄存器
  232. /// </summary>
  233. /// <param name="startAddress"></param>
  234. /// <param name="num"></param>
  235. /// <param name="slaveAddress"></param>
  236. /// <returns></returns>
  237. public ushort[] ReadInputRegisters(ushort startAddress, ushort num, byte slaveAddress = 1)
  238. {
  239. return master.ReadInputRegisters(slaveAddress, startAddress, num);
  240. }
  241. #endregion
  242. #region 批量数据写入
  243. /// <summary>
  244. /// 写入多个线圈
  245. /// </summary>
  246. /// <param name="startAddress"></param>
  247. /// <param name="value"></param>
  248. /// <param name="slaveAddress"></param>
  249. public void WriteMultipleCoils(ushort startAddress, bool[] value, byte slaveAddress = 1)
  250. {
  251. master.WriteMultipleCoils(slaveAddress, startAddress, value);
  252. }
  253. /// <summary>
  254. /// 写入多个寄存器
  255. /// </summary>
  256. /// <param name="startAddress"></param>
  257. /// <param name="value"></param>
  258. /// <param name="slaveAddress"></param>
  259. public void WriteMultipleRegisters(ushort startAddress, ushort[] value, byte slaveAddress = 1)
  260. {
  261. master.WriteMultipleRegisters(slaveAddress, startAddress, value);
  262. }
  263. #endregion
  264. #region 单个数据读取
  265. /// <summary>
  266. /// 读取单个线圈
  267. /// </summary>
  268. /// <param name="startAddress"></param>
  269. /// <param name="slaveAddress"></param>
  270. /// <returns></returns>
  271. public bool ReadCoils(ushort startAddress, byte slaveAddress = 1)
  272. {
  273. var result = master.ReadCoils(slaveAddress, startAddress, 1);
  274. if (result == null) return false;
  275. if (result.Length == 1) return result[0];
  276. return false;
  277. //return master.ReadCoils(slaveAddress, startAddress, 1)[0];
  278. }
  279. /// <summary>
  280. /// 读取单个输入线圈
  281. /// </summary>
  282. /// <param name="startAddress"></param>
  283. /// <param name="slaveAddress"></param>
  284. /// <returns></returns>
  285. public bool ReadInputs(ushort startAddress, byte slaveAddress = 1)
  286. {
  287. var result = master.ReadInputs(slaveAddress, startAddress, 1);
  288. if (result == null) return false;
  289. if (result.Length == 1) return result[0];
  290. return false;
  291. //return master.ReadInputs(slaveAddress, startAddress, 1)[0];
  292. }
  293. /// <summary>
  294. /// 读取单个保持寄存器
  295. /// </summary>
  296. /// <param name="startAddress"></param>
  297. /// <param name="slaveAddress"></param>
  298. /// <returns></returns>
  299. public ushort ReadHoldingRegisters(ushort startAddress, byte slaveAddress = 1)
  300. {
  301. if (tcpClient == null) return 0;
  302. ushort[] result = null;
  303. try
  304. {
  305. result = master.ReadHoldingRegisters(slaveAddress, startAddress, 1);
  306. }
  307. catch (Exception ex)
  308. {
  309. MessageLog.GetInstance.Show(ex.ToString());
  310. tcpClient = null;
  311. Connect();
  312. }
  313. if (result == null) return 0;
  314. if (result.Length == 1) return result[0];
  315. return 0;
  316. //return master.ReadHoldingRegisters(slaveAddress, startAddress, 1)[0];
  317. }
  318. /// <summary>
  319. /// 读取单个输入寄存器
  320. /// </summary>
  321. /// <param name="startAddress"></param>
  322. /// <param name="slaveAddress"></param>
  323. /// <returns></returns>
  324. public ushort ReadInputRegisters(ushort startAddress, byte slaveAddress = 1)
  325. {
  326. var result = master.ReadInputRegisters(slaveAddress, startAddress, 1);
  327. if (result == null) return 0;
  328. if (result.Length == 1) return result[0];
  329. return 0;
  330. //return master.ReadInputRegisters(slaveAddress, startAddress, 1)[0];
  331. }
  332. #endregion
  333. #region 单个数据写入
  334. /// <summary>
  335. /// 写入单个线圈
  336. /// </summary>
  337. /// <param name="startAddress"></param>
  338. /// <param name="value"></param>
  339. /// <param name="slaveAddress"></param>
  340. public void WriteSingleCoil(ushort startAddress, bool value, byte slaveAddress = 1)
  341. {
  342. master.WriteSingleCoil(slaveAddress, startAddress, value);
  343. }
  344. /// <summary>
  345. /// 写入单个寄存器
  346. /// </summary>
  347. /// <param name="startAddress"></param>
  348. /// <param name="value"></param>
  349. /// <param name="slaveAddress"></param>
  350. public void WriteSingleRegister(ushort startAddress, ushort value, byte slaveAddress = 1)
  351. {
  352. master.WriteSingleRegister(slaveAddress, startAddress, value);
  353. }
  354. #endregion
  355. }
  356. public enum ReadType
  357. {
  358. /// <summary>
  359. /// 读线圈
  360. /// </summary>
  361. Coils,
  362. /// <summary>
  363. /// 读输入线圈
  364. /// </summary>
  365. Inputs,
  366. /// <summary>
  367. /// 读保持寄存器
  368. /// </summary>
  369. HoldingRegisters,
  370. /// <summary>
  371. /// 读输入寄存器
  372. /// </summary>
  373. InputRegisters,
  374. }
  375. public enum WriteType
  376. {
  377. /// <summary>
  378. /// 写线圈
  379. /// </summary>
  380. Coils,
  381. /// <summary>
  382. /// 写保持寄存器
  383. /// </summary>
  384. HoldingRegisters,
  385. }
  386. }