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.
 
 

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