终端一体化运控平台
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.
 
 
 

545 lines
20 KiB

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