终端一体化运控平台
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

ModbusTcp.cs 17 KiB

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