终端一体化运控平台
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 

516 行
17 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 int GetBoolAddress(string address)
  102. {
  103. if (address != null && address.Length >= 4)
  104. {
  105. var res = address.Substring(1).Split('.');
  106. if (res != null && res.Length == 2)
  107. {
  108. if (int.TryParse(res[0], out int firstAddress) && int.TryParse(res[1], out int ExitAddress))
  109. {
  110. if (ExitAddress >= 0 && ExitAddress <= 7)
  111. {
  112. return (firstAddress * 8) + 320 + ExitAddress;
  113. }
  114. }
  115. }
  116. }
  117. return -1;
  118. }
  119. public int GetWordAddress(string address)
  120. {
  121. if (address != null && address.Length > 3)
  122. {
  123. var res = address.Substring(2);
  124. if (res != null && int.TryParse(res, out int tempAddress))
  125. {
  126. return (tempAddress / 2) + 100;
  127. }
  128. }
  129. return -1;
  130. }
  131. public void Readbool(ushort startAddress, ushort len, Action<bool[]> action)
  132. {
  133. object result;
  134. result = Read(startAddress, CommandType.Coils, len);
  135. if (result != null)
  136. {
  137. if (result is bool[] bools)
  138. {
  139. if (bools.Length == len)
  140. {
  141. action(bools);
  142. }
  143. }
  144. else if (result is bool bl)
  145. {
  146. List<bool> boolLists = new List<bool>();
  147. boolLists.Add(bl);
  148. action(boolLists.ToArray());
  149. }
  150. }
  151. }
  152. public object Read(ushort startAddress, CommandType readType, ushort num = 1, byte slaveAddress = 1)
  153. {
  154. object result = new object();
  155. if (tcpClient == null) return result;
  156. if (num <= 0) return result;
  157. try
  158. {
  159. switch (readType)
  160. {
  161. case CommandType.Coils:
  162. result = master.ReadCoils(slaveAddress, startAddress, num);
  163. break;
  164. case CommandType.Inputs:
  165. result = master.ReadInputs(slaveAddress, startAddress, num);
  166. break;
  167. case CommandType.HoldingRegisters:
  168. result = master.ReadHoldingRegisters(slaveAddress, startAddress, num);
  169. break;
  170. case CommandType.InputRegisters:
  171. result = master.ReadInputRegisters(slaveAddress, startAddress, num);
  172. break;
  173. default:
  174. break;
  175. }
  176. if (result == null) return new object();
  177. if (result is bool[] bools)
  178. {
  179. if (bools.Length == 1)
  180. return bools[0];
  181. else
  182. return bools;
  183. }
  184. if (result is ushort[] ushorts)
  185. {
  186. if (ushorts.Length == 1)
  187. return ushorts[0];
  188. else
  189. return ushorts;
  190. }
  191. }
  192. catch (Exception ex)
  193. {
  194. MessageLog.GetInstance.ShowEx($"读取地址:【{startAddress}】,读取类型:【{readType}】出错,{ex.ToString()}");
  195. if (ex.InnerException is SocketException)
  196. {
  197. tcpClient = null;
  198. Connect();
  199. }
  200. }
  201. return result;
  202. }
  203. public bool Write(ushort startAddress, CommandType writeType, object InputValue, byte slaveAddress = 1)
  204. {
  205. bool result = false;
  206. if (tcpClient == null) return result;
  207. if (!(InputValue is bool || InputValue is bool[] || InputValue is ushort || InputValue is ushort[])) return result;
  208. try
  209. {
  210. switch (writeType)
  211. {
  212. case CommandType.Coils:
  213. if (InputValue is bool boolValue)
  214. master.WriteSingleCoil(slaveAddress, startAddress, boolValue);
  215. if (InputValue is bool[] boolsValue)
  216. master.WriteMultipleCoils(slaveAddress, startAddress, boolsValue);
  217. break;
  218. case CommandType.HoldingRegisters:
  219. if (InputValue is ushort ushortValue)
  220. master.WriteSingleRegister(slaveAddress, startAddress, ushortValue);
  221. if (InputValue is ushort[] ushortsValue)
  222. {
  223. int len = 100;
  224. if (ushortsValue.Length > len)
  225. {
  226. List<ushort[]> ushortLists = new List<ushort[]>();
  227. for (int i = 0; i < ushortsValue.Length / len; i++)
  228. {
  229. ushortLists.Add(ushortsValue.Skip(0).Take(len).ToArray());
  230. }
  231. int y = ushortsValue.Length % len;
  232. if (y > 0)
  233. {
  234. ushortLists.Add(ushortsValue.Skip(ushortsValue.Length - y).Take(y).ToArray());
  235. }
  236. foreach (var item in ushortLists)
  237. {
  238. master.WriteMultipleRegisters(slaveAddress, startAddress, item);
  239. startAddress += (ushort)item.Length;
  240. }
  241. }
  242. else
  243. {
  244. master.WriteMultipleRegisters(slaveAddress, startAddress, ushortsValue);
  245. }
  246. }
  247. break;
  248. default:
  249. break;
  250. }
  251. }
  252. catch (Exception ex)
  253. {
  254. MessageLog.GetInstance.ShowEx(ex.ToString());
  255. if (ex.InnerException is SocketException)
  256. {
  257. tcpClient = null;
  258. Connect();
  259. }
  260. return false;
  261. }
  262. return true;
  263. }
  264. #region 批量数据读取
  265. /// <summary>
  266. /// 读取多个线圈
  267. /// </summary>
  268. /// <param name="startAddress"></param>
  269. /// <param name="num"></param>
  270. /// <param name="slaveAddress"></param>
  271. /// <returns></returns>
  272. public bool[] ReadCoils(ushort startAddress, ushort num, byte slaveAddress = 1)
  273. {
  274. return master.ReadCoils(slaveAddress, startAddress, num);
  275. }
  276. /// <summary>
  277. /// 读取多个输入线圈
  278. /// </summary>
  279. /// <param name="startAddress"></param>
  280. /// <param name="num"></param>
  281. /// <param name="slaveAddress"></param>
  282. /// <returns></returns>
  283. public bool[] ReadInputs(ushort startAddress, ushort num, byte slaveAddress = 1)
  284. {
  285. return master.ReadInputs(slaveAddress, startAddress, num);
  286. }
  287. /// <summary>
  288. /// 读取多个保持寄存器
  289. /// </summary>
  290. /// <param name="startAddress"></param>
  291. /// <param name="num"></param>
  292. /// <param name="slaveAddress"></param>
  293. /// <returns></returns>
  294. public ushort[] ReadHoldingRegisters(ushort startAddress, ushort num, byte slaveAddress = 1)
  295. {
  296. return master.ReadHoldingRegisters(slaveAddress, startAddress, num);
  297. }
  298. /// <summary>
  299. /// 读取多个输入寄存器
  300. /// </summary>
  301. /// <param name="startAddress"></param>
  302. /// <param name="num"></param>
  303. /// <param name="slaveAddress"></param>
  304. /// <returns></returns>
  305. public ushort[] ReadInputRegisters(ushort startAddress, ushort num, byte slaveAddress = 1)
  306. {
  307. return master.ReadInputRegisters(slaveAddress, startAddress, num);
  308. }
  309. #endregion
  310. #region 批量数据写入
  311. /// <summary>
  312. /// 写入多个线圈
  313. /// </summary>
  314. /// <param name="startAddress"></param>
  315. /// <param name="value"></param>
  316. /// <param name="slaveAddress"></param>
  317. public void WriteMultipleCoils(ushort startAddress, bool[] value, byte slaveAddress = 1)
  318. {
  319. master.WriteMultipleCoils(slaveAddress, startAddress, value);
  320. }
  321. /// <summary>
  322. /// 写入多个寄存器
  323. /// </summary>
  324. /// <param name="startAddress"></param>
  325. /// <param name="value"></param>
  326. /// <param name="slaveAddress"></param>
  327. public void WriteMultipleRegisters(ushort startAddress, ushort[] value, byte slaveAddress = 1)
  328. {
  329. master.WriteMultipleRegisters(slaveAddress, startAddress, value);
  330. }
  331. #endregion
  332. #region 单个数据读取
  333. /// <summary>
  334. /// 读取单个线圈
  335. /// </summary>
  336. /// <param name="startAddress"></param>
  337. /// <param name="slaveAddress"></param>
  338. /// <returns></returns>
  339. public bool ReadCoils(ushort startAddress, byte slaveAddress = 1)
  340. {
  341. var result = master.ReadCoils(slaveAddress, startAddress, 1);
  342. if (result == null) return false;
  343. if (result.Length == 1) return result[0];
  344. return false;
  345. //return master.ReadCoils(slaveAddress, startAddress, 1)[0];
  346. }
  347. /// <summary>
  348. /// 读取单个输入线圈
  349. /// </summary>
  350. /// <param name="startAddress"></param>
  351. /// <param name="slaveAddress"></param>
  352. /// <returns></returns>
  353. public bool ReadInputs(ushort startAddress, byte slaveAddress = 1)
  354. {
  355. var result = master.ReadInputs(slaveAddress, startAddress, 1);
  356. if (result == null) return false;
  357. if (result.Length == 1) return result[0];
  358. return false;
  359. //return master.ReadInputs(slaveAddress, startAddress, 1)[0];
  360. }
  361. /// <summary>
  362. /// 读取单个保持寄存器
  363. /// </summary>
  364. /// <param name="startAddress"></param>
  365. /// <param name="slaveAddress"></param>
  366. /// <returns></returns>
  367. public ushort ReadHoldingRegisters(ushort startAddress, byte slaveAddress = 1)
  368. {
  369. if (tcpClient == null) return 0;
  370. ushort[] result = null;
  371. try
  372. {
  373. result = master.ReadHoldingRegisters(slaveAddress, startAddress, 1);
  374. }
  375. catch (Exception ex)
  376. {
  377. MessageLog.GetInstance.Show(ex.ToString());
  378. tcpClient = null;
  379. Connect();
  380. }
  381. if (result == null) return 0;
  382. if (result.Length == 1) return result[0];
  383. return 0;
  384. //return master.ReadHoldingRegisters(slaveAddress, startAddress, 1)[0];
  385. }
  386. /// <summary>
  387. /// 读取单个输入寄存器
  388. /// </summary>
  389. /// <param name="startAddress"></param>
  390. /// <param name="slaveAddress"></param>
  391. /// <returns></returns>
  392. public ushort ReadInputRegisters(ushort startAddress, byte slaveAddress = 1)
  393. {
  394. var result = master.ReadInputRegisters(slaveAddress, startAddress, 1);
  395. if (result == null) return 0;
  396. if (result.Length == 1) return result[0];
  397. return 0;
  398. //return master.ReadInputRegisters(slaveAddress, startAddress, 1)[0];
  399. }
  400. #endregion
  401. #region 单个数据写入
  402. /// <summary>
  403. /// 写入单个线圈
  404. /// </summary>
  405. /// <param name="startAddress"></param>
  406. /// <param name="value"></param>
  407. /// <param name="slaveAddress"></param>
  408. public void WriteSingleCoil(ushort startAddress, bool value, byte slaveAddress = 1)
  409. {
  410. master.WriteSingleCoil(slaveAddress, startAddress, value);
  411. }
  412. /// <summary>
  413. /// 写入单个寄存器
  414. /// </summary>
  415. /// <param name="startAddress"></param>
  416. /// <param name="value"></param>
  417. /// <param name="slaveAddress"></param>
  418. public void WriteSingleRegister(ushort startAddress, ushort value, byte slaveAddress = 1)
  419. {
  420. master.WriteSingleRegister(slaveAddress, startAddress, value);
  421. }
  422. #endregion
  423. }
  424. public enum ReadType
  425. {
  426. /// <summary>
  427. /// 读线圈
  428. /// </summary>
  429. Coils,
  430. /// <summary>
  431. /// 读输入线圈
  432. /// </summary>
  433. Inputs,
  434. /// <summary>
  435. /// 读保持寄存器
  436. /// </summary>
  437. HoldingRegisters,
  438. /// <summary>
  439. /// 读输入寄存器
  440. /// </summary>
  441. InputRegisters,
  442. }
  443. public enum WriteType
  444. {
  445. /// <summary>
  446. /// 写线圈
  447. /// </summary>
  448. Coils,
  449. /// <summary>
  450. /// 写保持寄存器
  451. /// </summary>
  452. HoldingRegisters,
  453. }
  454. public enum CommandType
  455. {
  456. /// <summary>
  457. /// 线圈操作
  458. /// </summary>
  459. Coils,
  460. /// <summary>
  461. /// 输入线圈操作
  462. /// </summary>
  463. Inputs,
  464. /// <summary>
  465. /// 保持寄存器操作
  466. /// </summary>
  467. HoldingRegisters,
  468. /// <summary>
  469. /// 输入寄存器操作
  470. /// </summary>
  471. InputRegisters,
  472. }
  473. }