终端一体化运控平台
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

465 lines
16 KiB

  1. using BPASmartClient.Helper;
  2. using BPASmartClient.Message;
  3. using NModbus;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Net.Sockets;
  8. using System.Text;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. namespace BPASmartClient.Modbus
  12. {
  13. public class ModbusTcp
  14. {
  15. //private volatile static ModbusTcp _Instance;
  16. //public static ModbusTcp GetInstance => _Instance ?? (_Instance = new ModbusTcp());
  17. //private ModbusTcp() { }
  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. MessageLog.GetInstance.Show($"设备【{ip}:{port}】连接成功");
  44. }
  45. private void Connect()
  46. {
  47. bool ErrorFlag = false;
  48. while (!Connected)
  49. {
  50. try
  51. {
  52. tcpClient = new TcpClient(IPAdress, Port);
  53. master = modbusFactory.CreateMaster(tcpClient);
  54. }
  55. catch (Exception ex)
  56. {
  57. if (!ErrorFlag)
  58. {
  59. MessageLog.GetInstance.ShowEx($"ModbusTcp 连接失败,IP = {IPAdress},Port = {Port}");
  60. MessageLog.GetInstance.ShowEx(ex.ToString());
  61. ErrorFlag = true;
  62. }
  63. Thread.Sleep(3000);
  64. }
  65. }
  66. MessageLog.GetInstance.Show("ModbusTcp 连接成功!");
  67. }
  68. /// <summary>
  69. /// 获取 M 区 和 VW 区的Modbus的地址
  70. /// </summary>
  71. /// <param name="address"></param>
  72. /// <returns></returns>
  73. public int GetAddress(string address)
  74. {
  75. if (address == null) return -1;
  76. if (address.Length > 0)
  77. {
  78. if (address.ToUpper().Contains("M") && address.Length >= 4)
  79. {
  80. var res = address.Substring(1).Split('.');
  81. if (res != null && res.Length == 2)
  82. {
  83. if (int.TryParse(res[0], out int firstAddress) && int.TryParse(res[1], out int ExitAddress))
  84. {
  85. if (ExitAddress >= 0 && ExitAddress <= 7)
  86. {
  87. return (firstAddress * 8) + 320 + ExitAddress;
  88. }
  89. }
  90. }
  91. }
  92. else if (address.ToUpper().Contains("VW") && address.Length >= 3)
  93. {
  94. var res = address.Substring(2);
  95. if (res != null && int.TryParse(res, out int tempAddress))
  96. {
  97. return (tempAddress / 2) + 100;
  98. }
  99. }
  100. }
  101. return -1;
  102. }
  103. public object Read(string address, ushort len = 1, byte slaveAddress = 1)
  104. {
  105. if (address == null || tcpClient == null) return default(object);
  106. ushort startAddress = (ushort)GetAddress(address);
  107. CommandType commandType = CommandType.Coils;
  108. try
  109. {
  110. if (address.ToUpper().Contains("M"))
  111. {
  112. commandType = CommandType.Coils;
  113. return master.ReadCoils(slaveAddress, startAddress, len);
  114. }
  115. else if (address.ToUpper().Contains("VW"))
  116. {
  117. commandType = CommandType.HoldingRegisters;
  118. return master.ReadHoldingRegisters(slaveAddress, startAddress, len);
  119. }
  120. else if (address.ToUpper().Contains("I"))
  121. {
  122. commandType = CommandType.Inputs;
  123. return master.ReadInputs(slaveAddress, startAddress, len);
  124. }
  125. }
  126. catch (Exception ex)
  127. {
  128. MessageLog.GetInstance.ShowEx($"读取地址:【{address}:= {startAddress}】,读取类型:【{commandType.ToString()}】出错,{ex.ToString()}");
  129. if (ex.InnerException is SocketException)
  130. {
  131. tcpClient = null;
  132. Connect();
  133. }
  134. }
  135. return default(object);
  136. }
  137. public void Write<T>(string address, T value, byte slaveAddress = 1)
  138. {
  139. if (address == null || tcpClient == null) return;
  140. ushort startAddress = (ushort)GetAddress(address);
  141. CommandType commandType = CommandType.Coils;
  142. try
  143. {
  144. if (address.ToUpper().Contains("M"))
  145. {
  146. commandType = CommandType.Coils;
  147. if (value is bool boolValue)
  148. master.WriteSingleCoil(slaveAddress, startAddress, boolValue);
  149. else if (value is bool[] boolsValue)
  150. master.WriteMultipleCoils(slaveAddress, startAddress, boolsValue);
  151. }
  152. else if (address.ToUpper().Contains("VW"))
  153. {
  154. commandType = CommandType.HoldingRegisters;
  155. if (value is ushort ushortValue)
  156. master.WriteSingleRegister(slaveAddress, startAddress, ushortValue);
  157. else if (value is ushort[] ushortsValue)
  158. {
  159. int len = 100;
  160. if (ushortsValue.Length > len)
  161. {
  162. List<ushort[]> ushortLists = new List<ushort[]>();
  163. for (int i = 0; i < ushortsValue.Length / len; i++)
  164. {
  165. ushortLists.Add(ushortsValue.Skip(0).Take(len).ToArray());
  166. }
  167. int y = ushortsValue.Length % len;
  168. if (y > 0)
  169. {
  170. ushortLists.Add(ushortsValue.Skip(ushortsValue.Length - y).Take(y).ToArray());
  171. }
  172. foreach (var item in ushortLists)
  173. {
  174. master.WriteMultipleRegisters(slaveAddress, startAddress, item);
  175. startAddress += (ushort)item.Length;
  176. }
  177. }
  178. else
  179. {
  180. master.WriteMultipleRegisters(slaveAddress, startAddress, ushortsValue);
  181. }
  182. }
  183. }
  184. else if (address.ToUpper().Contains("I"))
  185. {
  186. commandType = CommandType.Inputs;
  187. }
  188. }
  189. catch (Exception ex)
  190. {
  191. MessageLog.GetInstance.ShowEx($"读写入地址:【{address}:= {startAddress}】,写入类型:【{commandType.ToString()}】出错,{ex.ToString()}");
  192. if (ex.InnerException is SocketException)
  193. {
  194. tcpClient = null;
  195. Connect();
  196. }
  197. }
  198. }
  199. #region 字符串数据读写
  200. /// <summary>
  201. /// 赋值string
  202. /// </summary>
  203. /// <param name="StartAddress"></param>
  204. /// <param name="value"></param>
  205. /// <returns></returns>
  206. public void SetString(string StartAddress, string value)
  207. {
  208. var bytes = Encoding.UTF8.GetBytes(value);
  209. Write(StartAddress, bytes.BytesToUshorts());
  210. }
  211. /// <summary>
  212. /// 获取string
  213. /// </summary>
  214. /// <param name="StartAddress"></param>
  215. /// <param name="len"></param>
  216. /// <returns></returns>
  217. public string GetString(string StartAddress, ushort len)
  218. {
  219. var res = Read(StartAddress, len);
  220. if (res != null && res is ushort[] ushorts)
  221. {
  222. return Encoding.UTF8.GetString(ushorts.UshortsToBytes()).Trim(new char[] { '\0' });
  223. }
  224. return String.Empty;
  225. }
  226. #endregion
  227. #region 浮点数数据读写
  228. /// <summary>
  229. /// 赋值Real类型数据
  230. /// </summary>
  231. /// <param name="StartAddress"></param>
  232. /// <param name="value"></param>
  233. public void SetReal(string StartAddress, float value)
  234. {
  235. var bytes = BitConverter.GetBytes(value);
  236. Write(StartAddress, bytes.BytesToUshorts());
  237. }
  238. /// <summary>
  239. /// 获取float类型数据
  240. /// </summary>
  241. /// <param name="StartAddress"></param>
  242. /// <returns></returns>
  243. public float GetReal(string StartAddress)
  244. {
  245. var res = Read(StartAddress, 2);
  246. if (res != null && res is ushort[] ushorts)
  247. {
  248. return BitConverter.ToSingle(ushorts.UshortsToBytes(), 0);
  249. }
  250. return 0;
  251. }
  252. #endregion
  253. #region 批量数据读取
  254. /// <summary>
  255. /// 读取多个线圈
  256. /// </summary>
  257. /// <param name="startAddress"></param>
  258. /// <param name="num"></param>
  259. /// <param name="slaveAddress"></param>
  260. /// <returns></returns>
  261. public bool[] ReadCoils(ushort startAddress, ushort num, byte slaveAddress = 1)
  262. {
  263. return master.ReadCoils(slaveAddress, startAddress, num);
  264. }
  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[] ReadInputs(ushort startAddress, ushort num, byte slaveAddress = 1)
  273. {
  274. return master.ReadInputs(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 ushort[] ReadHoldingRegisters(ushort startAddress, ushort num, byte slaveAddress = 1)
  284. {
  285. return master.ReadHoldingRegisters(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[] ReadInputRegisters(ushort startAddress, ushort num, byte slaveAddress = 1)
  295. {
  296. return master.ReadInputRegisters(slaveAddress, startAddress, num);
  297. }
  298. #endregion
  299. #region 批量数据写入
  300. /// <summary>
  301. /// 写入多个线圈
  302. /// </summary>
  303. /// <param name="startAddress"></param>
  304. /// <param name="value"></param>
  305. /// <param name="slaveAddress"></param>
  306. public void WriteMultipleCoils(ushort startAddress, bool[] value, byte slaveAddress = 1)
  307. {
  308. master.WriteMultipleCoils(slaveAddress, startAddress, value);
  309. }
  310. /// <summary>
  311. /// 写入多个寄存器
  312. /// </summary>
  313. /// <param name="startAddress"></param>
  314. /// <param name="value"></param>
  315. /// <param name="slaveAddress"></param>
  316. public void WriteMultipleRegisters(ushort startAddress, ushort[] value, byte slaveAddress = 1)
  317. {
  318. master.WriteMultipleRegisters(slaveAddress, startAddress, value);
  319. }
  320. #endregion
  321. #region 单个数据读取
  322. /// <summary>
  323. /// 读取单个线圈
  324. /// </summary>
  325. /// <param name="startAddress"></param>
  326. /// <param name="slaveAddress"></param>
  327. /// <returns></returns>
  328. public bool ReadCoils(ushort startAddress, byte slaveAddress = 1)
  329. {
  330. var result = master.ReadCoils(slaveAddress, startAddress, 1);
  331. if (result == null) return false;
  332. if (result.Length == 1) return result[0];
  333. return false;
  334. //return master.ReadCoils(slaveAddress, startAddress, 1)[0];
  335. }
  336. /// <summary>
  337. /// 读取单个输入线圈
  338. /// </summary>
  339. /// <param name="startAddress"></param>
  340. /// <param name="slaveAddress"></param>
  341. /// <returns></returns>
  342. public bool ReadInputs(ushort startAddress, byte slaveAddress = 1)
  343. {
  344. var result = master.ReadInputs(slaveAddress, startAddress, 1);
  345. if (result == null) return false;
  346. if (result.Length == 1) return result[0];
  347. return false;
  348. //return master.ReadInputs(slaveAddress, startAddress, 1)[0];
  349. }
  350. /// <summary>
  351. /// 读取单个保持寄存器
  352. /// </summary>
  353. /// <param name="startAddress"></param>
  354. /// <param name="slaveAddress"></param>
  355. /// <returns></returns>
  356. public ushort ReadHoldingRegisters(ushort startAddress, byte slaveAddress = 1)
  357. {
  358. if (tcpClient == null) return 0;
  359. ushort[] result = null;
  360. try
  361. {
  362. result = master.ReadHoldingRegisters(slaveAddress, startAddress, 1);
  363. }
  364. catch (Exception ex)
  365. {
  366. MessageLog.GetInstance.Show(ex.ToString());
  367. tcpClient = null;
  368. Connect();
  369. }
  370. if (result == null) return 0;
  371. if (result.Length == 1) return result[0];
  372. return 0;
  373. //return master.ReadHoldingRegisters(slaveAddress, startAddress, 1)[0];
  374. }
  375. /// <summary>
  376. /// 读取单个输入寄存器
  377. /// </summary>
  378. /// <param name="startAddress"></param>
  379. /// <param name="slaveAddress"></param>
  380. /// <returns></returns>
  381. public ushort ReadInputRegisters(ushort startAddress, byte slaveAddress = 1)
  382. {
  383. var result = master.ReadInputRegisters(slaveAddress, startAddress, 1);
  384. if (result == null) return 0;
  385. if (result.Length == 1) return result[0];
  386. return 0;
  387. //return master.ReadInputRegisters(slaveAddress, startAddress, 1)[0];
  388. }
  389. #endregion
  390. #region 单个数据写入
  391. /// <summary>
  392. /// 写入单个线圈
  393. /// </summary>
  394. /// <param name="startAddress"></param>
  395. /// <param name="value"></param>
  396. /// <param name="slaveAddress"></param>
  397. public void WriteSingleCoil(ushort startAddress, bool value, byte slaveAddress = 1)
  398. {
  399. master.WriteSingleCoil(slaveAddress, startAddress, value);
  400. }
  401. /// <summary>
  402. /// 写入单个寄存器
  403. /// </summary>
  404. /// <param name="startAddress"></param>
  405. /// <param name="value"></param>
  406. /// <param name="slaveAddress"></param>
  407. public void WriteSingleRegister(ushort startAddress, ushort value, byte slaveAddress = 1)
  408. {
  409. master.WriteSingleRegister(slaveAddress, startAddress, value);
  410. }
  411. #endregion
  412. }
  413. public enum CommandType
  414. {
  415. /// <summary>
  416. /// 线圈操作
  417. /// </summary>
  418. Coils,
  419. /// <summary>
  420. /// 输入线圈操作
  421. /// </summary>
  422. Inputs,
  423. /// <summary>
  424. /// 保持寄存器操作
  425. /// </summary>
  426. HoldingRegisters,
  427. /// <summary>
  428. /// 输入寄存器操作
  429. /// </summary>
  430. InputRegisters,
  431. }
  432. }