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

747 lines
28 KiB

  1. using NModbus;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Linq;
  6. using System.Net.Sockets;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using BPA.Helper;
  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 ManualResetEvent mre = new ManualResetEvent(false);
  22. public string IPAdress;
  23. public int Port;
  24. public Action<string> Show { get; set; }
  25. public Action<string> ShowEx { get; set; }
  26. /// <summary>
  27. /// 连接plc 原料设备成功
  28. /// </summary>
  29. public Action ConnectOk { get; set; }
  30. public Action ConnectFail { get; set; }
  31. public Action Disconnect { get; set; }
  32. public bool IsReconnect { get; set; } = false; //true=启用重连,false=禁用重连
  33. /// <summary>
  34. /// 判断是否连接成功
  35. /// </summary>
  36. public bool Connected => tcpClient == null ? false : tcpClient.Connected;
  37. /// <summary>
  38. /// ModbusTcp 连接设备
  39. /// </summary>
  40. /// <param name="ip">ip 地址</param>
  41. /// <param name="port">端口号,默认502</param>
  42. public void ModbusTcpConnect(string ip, int port = 502)
  43. {
  44. Show?.Invoke($"设备【{ip}:{port}】连接中。。。。");
  45. IPAdress = ip;
  46. Port = port;
  47. modbusFactory = new ModbusFactory();
  48. Connect();
  49. if (Connected)
  50. {
  51. master.Transport.ReadTimeout = 3000;//读取超时时间
  52. master.Transport.WriteTimeout = 3000;//写入超时时间
  53. master.Transport.Retries = 10;//重试次数
  54. ConnectOk?.Invoke();
  55. Show?.Invoke($"设备【{ip}:{port}】连接成功");
  56. }
  57. else
  58. {
  59. ConnectFail?.Invoke();
  60. }
  61. }
  62. public void Dispose()
  63. {
  64. master.Dispose();
  65. Disconnect?.Invoke();
  66. }
  67. private void Connect()
  68. {
  69. bool ErrorFlag = false;
  70. while (!Connected)
  71. {
  72. try
  73. {
  74. tcpClient = new TcpClient(IPAdress, Port);
  75. //mre.Reset();
  76. //tcpClient.BeginConnect(IPAdress, Port, (res) => { mre.Set(); }, null);
  77. //if (!mre.WaitOne(1500, false)) break;
  78. master = modbusFactory.CreateMaster(tcpClient);
  79. }
  80. catch (Exception ex)
  81. {
  82. if (!ErrorFlag)
  83. {
  84. ShowEx?.Invoke($"ModbusTcp 连接失败,IP = {IPAdress},Port = {Port}");
  85. ShowEx?.Invoke(ex.ToString());
  86. ErrorFlag = true;
  87. }
  88. if (!IsReconnect) break;
  89. Thread.Sleep(3000);
  90. }
  91. }
  92. if (ErrorFlag && IsReconnect) Show?.Invoke("ModbusTcp 重连成功!");
  93. }
  94. /// <summary>
  95. /// 获取 M 区 和 VW 区的Modbus的地址
  96. /// </summary>
  97. /// <param name="address"></param>
  98. /// <returns></returns>
  99. public int GetAddress(string address)
  100. {
  101. if (address == null) return -1;
  102. if (address.Length > 0)
  103. {
  104. address = address.Trim();
  105. if (address.ToUpper().Contains("GM") && address.Length >= 3)
  106. {
  107. var res = address.Remove(0, 2);
  108. if (res != null && res.Length > 0)
  109. {
  110. return int.Parse(res) + 4096;
  111. }
  112. }
  113. else if (address.ToUpper().Contains("M") && address.Length >= 4)
  114. {
  115. var res = address.Substring(1).Split('.');
  116. if (res != null && res.Length == 2)
  117. {
  118. if (int.TryParse(res[0], out int firstAddress) && int.TryParse(res[1], out int ExitAddress))
  119. {
  120. if (ExitAddress >= 0 && ExitAddress <= 7)
  121. {
  122. return (firstAddress * 8) + 320 + ExitAddress;
  123. }
  124. }
  125. }
  126. }
  127. else if (address.ToUpper().Contains("I") && address.Length >= 2)
  128. {
  129. var res = address.Substring(1).Split('.');
  130. if (res != null && res.Length == 2)
  131. {
  132. if (int.TryParse(res[0], out int firstAddress) && int.TryParse(res[1], out int ExitAddress))
  133. {
  134. if (ExitAddress >= 0 && ExitAddress <= 7)
  135. {
  136. return (firstAddress * 8) + ExitAddress;
  137. }
  138. }
  139. }
  140. }
  141. else if (address.ToUpper().Contains("GI") && address.Length >= 3)
  142. {
  143. var res = address.Remove(0, 2);
  144. if (res != null && res.Length > 0)
  145. {
  146. return int.Parse(res);
  147. }
  148. }
  149. else if (address.ToUpper().Contains("LB") && address.Length >= 3)
  150. {
  151. var res = address.Substring(2);
  152. if (res != null && res.Length > 0)
  153. {
  154. if (int.TryParse(res, out int firstAddress))
  155. {
  156. return firstAddress;
  157. }
  158. }
  159. }
  160. else if ((address.ToUpper().Contains("VW") || address.ToUpper().Contains("VD")) && address.Length >= 3)
  161. {
  162. var res = address.Substring(2);
  163. if (res != null && int.TryParse(res, out int tempAddress))
  164. {
  165. return (tempAddress / 2) + 100;
  166. }
  167. }
  168. else if (address.ToUpper().Contains("LW") && address.Length >= 3)
  169. {
  170. var res = address.Substring(2);
  171. if (res != null && int.TryParse(res, out int LwAddress))
  172. {
  173. return LwAddress;
  174. }
  175. }
  176. else if (address.ToUpper().Contains("D") && address.Length == 5)
  177. {
  178. try
  179. {
  180. //D1001
  181. string head = (Convert.ToInt32(address.Substring(1, 1))).ToString();
  182. int num = Convert.ToInt32(address.Substring(2, 3));
  183. int len = num.ToString().Length;
  184. string tail = string.Empty;
  185. switch (len)
  186. {
  187. case 1:
  188. if ((Convert.ToInt32(address.Substring(4, 1))).ToString().Length > 1)
  189. {
  190. tail = "0" + (Convert.ToInt32(address.Substring(4, 1))).ToString();
  191. }
  192. else
  193. {
  194. tail = "00" + (Convert.ToInt32(address.Substring(4, 1))).ToString();
  195. }
  196. break;
  197. case 2:
  198. if ((Convert.ToInt32(address.Substring(3, 2))).ToString().Length > 2)
  199. {
  200. tail = (Convert.ToInt32(address.Substring(3, 2))).ToString();
  201. }
  202. else
  203. {
  204. tail = "0" + (Convert.ToInt32(address.Substring(3, 2))).ToString();
  205. }
  206. break;
  207. case 3:
  208. tail = (Convert.ToInt32(address.Substring(2, 3))).ToString();
  209. break;
  210. }
  211. address = head + tail;
  212. return Convert.ToInt32(address);
  213. }
  214. catch (Exception)
  215. {
  216. //打印日志
  217. }
  218. }
  219. }
  220. return -1;
  221. }
  222. private void ExceptionHandling(Exception ex)
  223. {
  224. if (ex.InnerException is SocketException)
  225. {
  226. if (IsReconnect)
  227. {
  228. tcpClient = null;
  229. Connect();
  230. }
  231. Disconnect?.Invoke();
  232. }
  233. }
  234. public short ReadShort(string address)
  235. {
  236. var res = Read(address);
  237. if (res != null && res is short[] shorts && shorts.Length == 1)
  238. {
  239. return shorts[0];
  240. }
  241. return 0;
  242. }
  243. public object Read(string address, ushort len = 1, byte slaveAddress = 1)
  244. {
  245. if (address == null || tcpClient == null) return default(object);
  246. ushort startAddress = (ushort)GetAddress(address);
  247. CommandType commandType = CommandType.Coils;
  248. try
  249. {
  250. if (address.ToUpper().Contains("M") || address.ToUpper().Contains("GM"))
  251. {
  252. commandType = CommandType.Coils;
  253. return master.ReadCoils(slaveAddress, startAddress, len);
  254. }
  255. else if (address.ToUpper().Contains("VD"))
  256. {
  257. commandType = CommandType.HoldingRegisters;
  258. var var1 = master.ReadHoldingRegisters(slaveAddress, startAddress, len);
  259. var var2 = master.ReadHoldingRegisters(slaveAddress, (ushort)(startAddress + 1), len);
  260. int dest = 0;
  261. dest |= (var2[0] & 0x0000ffff);
  262. dest = (dest << 16) | (var1[0] & 0x0000ffff);
  263. return dest;
  264. }
  265. else if (address.ToUpper().Contains("VW") || address.ToUpper().Contains("LW") || address.ToUpper().Contains("D"))
  266. {
  267. commandType = CommandType.HoldingRegisters;
  268. return master.ReadHoldingRegisters(slaveAddress, startAddress, len);
  269. }
  270. else if (address.ToUpper().Contains("VD"))
  271. {
  272. commandType = CommandType.HoldingRegisters;
  273. var var1 = master.ReadHoldingRegisters(slaveAddress, startAddress, len);
  274. var var2 = master.ReadHoldingRegisters(slaveAddress, (ushort)(startAddress + 2), len);
  275. int dest = 0;
  276. dest |= (var2[0] & 0x0000ffff);
  277. dest = (dest << 16) | (var1[0] & 0x0000ffff);
  278. return dest;
  279. }
  280. else if (address.ToUpper().Contains("I"))
  281. {
  282. commandType = CommandType.Inputs;
  283. return master.ReadInputs(slaveAddress, startAddress, len);
  284. }
  285. else if (address.ToUpper().Contains("LB"))
  286. {
  287. commandType = CommandType.Coils;
  288. return master.ReadCoils(slaveAddress, startAddress, len);
  289. }
  290. }
  291. catch (Exception ex)
  292. {
  293. ShowEx?.Invoke($"读取地址:【{address}:= {startAddress}】,读取类型:【{commandType.ToString()}】出错,{ex.ToString()}");
  294. ExceptionHandling(ex);
  295. }
  296. return default(object);
  297. }
  298. /// <summary>
  299. /// 写入数据
  300. /// </summary>
  301. /// <typeparam name="T"></typeparam>
  302. /// <param name="address">写入地址</param>
  303. /// <param name="value">写入值</param>
  304. /// <param name="Retries">重试次数</param>
  305. /// <param name="slaveAddress">从站地址</param>
  306. /// <returns></returns>
  307. public bool Write<T>(string address, T value, int Retries = 1, byte slaveAddress = 1)
  308. {
  309. int count = 0;
  310. if (Retries == 1 || Retries == 0)
  311. {
  312. return TempWrite(address, value, slaveAddress);
  313. }
  314. else if (Retries > 1)
  315. {
  316. bool isok = false;
  317. while (count < Retries)
  318. {
  319. count++;
  320. TempWrite(address, value, slaveAddress);
  321. var res = Read(address);
  322. if (res != null && res.ToString() == value.ToString())
  323. {
  324. isok = true;
  325. break;
  326. }
  327. }
  328. return isok;
  329. }
  330. return false;
  331. }
  332. private bool TempWrite<T>(string address, T value, byte slaveAddress = 1)
  333. {
  334. if (address == null || tcpClient == null)
  335. {
  336. //Show?.Invoke("写入失败,地址为空或断开连接");
  337. return false;
  338. }
  339. ushort startAddress = (ushort)GetAddress(address);
  340. CommandType commandType = CommandType.Coils;
  341. try
  342. {
  343. if (address.ToUpper().Contains("M"))
  344. {
  345. commandType = CommandType.Coils;
  346. if (value is bool boolValue)
  347. master.WriteSingleCoil(slaveAddress, startAddress, boolValue);
  348. else if (value is bool[] boolsValue)
  349. master.WriteMultipleCoils(slaveAddress, startAddress, boolsValue);
  350. else return false;
  351. }
  352. if (address.ToUpper().Contains("GM") && address.Length >= 3)
  353. {
  354. commandType = CommandType.Coils;
  355. if (value is bool boolValue)
  356. master.WriteSingleCoil(slaveAddress, startAddress, boolValue);
  357. else if (value is bool[] boolsValue)
  358. master.WriteMultipleCoils(slaveAddress, startAddress, boolsValue);
  359. else return false;
  360. }
  361. else if (address.ToUpper().Contains("LB"))
  362. {
  363. commandType = CommandType.Coils;
  364. if (value is bool boolValue)
  365. master.WriteSingleCoil(slaveAddress, startAddress, boolValue);
  366. else if (value is bool[] boolsValue)
  367. master.WriteMultipleCoils(slaveAddress, startAddress, boolsValue);
  368. else return false;
  369. }
  370. else if (address.ToUpper().Contains("VD"))
  371. {
  372. commandType = CommandType.HoldingRegisters;
  373. if (value is int intValue)
  374. {
  375. var val1 = (UInt16)intValue;
  376. var val2 = Convert.ToUInt16(intValue >> 16 & 0x0000ffff);
  377. master.WriteSingleRegister(slaveAddress, startAddress, val1);
  378. master.WriteSingleRegister(slaveAddress, (ushort)(startAddress + 1), val2);
  379. }
  380. else return false;
  381. }
  382. else if (address.ToUpper().Contains("VW") || address.ToUpper().Contains("LW") || address.ToUpper().Contains("D"))
  383. {
  384. commandType = CommandType.HoldingRegisters;
  385. if (value is ushort ushortValue)
  386. master.WriteSingleRegister(slaveAddress, startAddress, ushortValue);
  387. else if (value is ushort[] ushortsValue)
  388. {
  389. int len = 100;
  390. if (ushortsValue.Length > len)
  391. {
  392. List<ushort[]> ushortLists = new List<ushort[]>();
  393. for (int i = 0; i < ushortsValue.Length / len; i++)
  394. {
  395. ushortLists.Add(ushortsValue.Skip(0).Take(len).ToArray());
  396. }
  397. int y = ushortsValue.Length % len;
  398. if (y > 0)
  399. {
  400. ushortLists.Add(ushortsValue.Skip(ushortsValue.Length - y).Take(y).ToArray());
  401. }
  402. foreach (var item in ushortLists)
  403. {
  404. master.WriteMultipleRegisters(slaveAddress, startAddress, item);
  405. startAddress += (ushort)item.Length;
  406. }
  407. }
  408. else
  409. {
  410. master.WriteMultipleRegisters(slaveAddress, startAddress, ushortsValue);
  411. }
  412. }
  413. else return false;
  414. }
  415. else if (address.ToUpper().Contains("I"))
  416. {
  417. commandType = CommandType.Inputs;
  418. }
  419. //Show?.Invoke($"成功,地址:{address},值:{value}");
  420. return true;
  421. }
  422. catch (Exception ex)
  423. {
  424. ShowEx?.Invoke($"写入地址:【{address}:= {startAddress}】,写入类型:【{commandType.ToString()}】出错,{ex.ToString()}");
  425. ExceptionHandling(ex);
  426. return false;
  427. }
  428. }
  429. #region 字符串数据读写
  430. /// <summary>
  431. /// 赋值string
  432. /// </summary>
  433. /// <param name="StartAddress"></param>
  434. /// <param name="value"></param>
  435. /// <returns></returns>
  436. public void SetString(string StartAddress, string value)
  437. {
  438. //获取指定的编码不存在的时候需要安装 System.Text.Encoding.CodePages nuget包
  439. //然后使用下面的代码就可以获取了
  440. Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
  441. var bytes = Encoding.GetEncoding("gb2312")?.GetBytes(value);
  442. Write(StartAddress, bytes.ToUshorts());
  443. }
  444. /// <summary>
  445. /// 获取string
  446. /// </summary>
  447. /// <param name="StartAddress"></param>
  448. /// <param name="len"></param>
  449. /// <returns></returns>
  450. public string GetString(string StartAddress, ushort len)
  451. {
  452. var res = Read(StartAddress, len);
  453. if (res != null && res is ushort[] ushorts)
  454. {
  455. Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
  456. return Encoding.GetEncoding("gb2312")?.GetString(ushorts.ToBytes()).Trim(new char[] { '\0' });
  457. }
  458. return String.Empty;
  459. }
  460. #endregion
  461. #region 浮点数数据读写
  462. /// <summary>
  463. /// 赋值Real类型数据
  464. /// </summary>
  465. /// <param name="StartAddress"></param>
  466. /// <param name="value"></param>
  467. public bool SetReal(string StartAddress, float value, int Retries = 1)
  468. {
  469. var bytes = BitConverter.GetBytes(value);
  470. return Write(StartAddress, bytes.ToUshorts(), Retries);
  471. }
  472. /// <summary>
  473. /// 获取float类型数据
  474. /// </summary>
  475. /// <param name="StartAddress"></param>
  476. /// <returns></returns>
  477. public float GetReal(string StartAddress)
  478. {
  479. var res = Read(StartAddress, 2);
  480. if (res != null && res is ushort[] ushorts)
  481. {
  482. return BitConverter.ToSingle(ushorts.ToBytes(), 0);
  483. }
  484. return 0;
  485. }
  486. #endregion
  487. #region 整数数据读写
  488. /// <summary>
  489. /// 赋值Real类型数据
  490. /// </summary>
  491. /// <param name="StartAddress"></param>
  492. /// <param name="value"></param>
  493. public void SetUint(string StartAddress, uint value)
  494. {
  495. var bytes = BitConverter.GetBytes(value);
  496. Write(StartAddress, bytes.ToUshorts());
  497. }
  498. /// <summary>
  499. /// 获取float类型数据
  500. /// </summary>
  501. /// <param name="StartAddress"></param>
  502. /// <returns></returns>
  503. public uint GetUint(string StartAddress)
  504. {
  505. var res = Read(StartAddress, 2);
  506. if (res != null && res is ushort[] ushorts)
  507. {
  508. return BitConverter.ToUInt32(ushorts.ToBytes(), 0);
  509. }
  510. return 0;
  511. }
  512. #endregion
  513. #region 批量数据读取
  514. /// <summary>
  515. /// 读取多个线圈
  516. /// </summary>
  517. /// <param name="startAddress"></param>
  518. /// <param name="num"></param>
  519. /// <param name="slaveAddress"></param>
  520. /// <returns></returns>
  521. public bool[] ReadCoils(ushort startAddress, ushort num, byte slaveAddress = 1)
  522. {
  523. return master.ReadCoils(slaveAddress, startAddress, num);
  524. }
  525. /// <summary>
  526. /// 读取多个输入线圈
  527. /// </summary>
  528. /// <param name="startAddress"></param>
  529. /// <param name="num"></param>
  530. /// <param name="slaveAddress"></param>
  531. /// <returns></returns>
  532. public bool[] ReadInputs(ushort startAddress, ushort num, byte slaveAddress = 1)
  533. {
  534. return master.ReadInputs(slaveAddress, startAddress, num);
  535. }
  536. /// <summary>
  537. /// 读取多个保持寄存器
  538. /// </summary>
  539. /// <param name="startAddress"></param>
  540. /// <param name="num"></param>
  541. /// <param name="slaveAddress"></param>
  542. /// <returns></returns>
  543. public ushort[] ReadHoldingRegisters(ushort startAddress, ushort num, byte slaveAddress = 1)
  544. {
  545. return master.ReadHoldingRegisters(slaveAddress, startAddress, num);
  546. }
  547. /// <summary>
  548. /// 读取多个输入寄存器
  549. /// </summary>
  550. /// <param name="startAddress"></param>
  551. /// <param name="num"></param>
  552. /// <param name="slaveAddress"></param>
  553. /// <returns></returns>
  554. public ushort[] ReadInputRegisters(ushort startAddress, ushort num, byte slaveAddress = 1)
  555. {
  556. return master.ReadInputRegisters(slaveAddress, startAddress, num);
  557. }
  558. #endregion
  559. #region 批量数据写入
  560. /// <summary>
  561. /// 写入多个线圈
  562. /// </summary>
  563. /// <param name="startAddress"></param>
  564. /// <param name="value"></param>
  565. /// <param name="slaveAddress"></param>
  566. public void WriteMultipleCoils(ushort startAddress, bool[] value, byte slaveAddress = 1)
  567. {
  568. master.WriteMultipleCoils(slaveAddress, startAddress, value);
  569. }
  570. /// <summary>
  571. /// 写入多个寄存器
  572. /// </summary>
  573. /// <param name="startAddress"></param>
  574. /// <param name="value"></param>
  575. /// <param name="slaveAddress"></param>
  576. public void WriteMultipleRegisters(ushort startAddress, ushort[] value, byte slaveAddress = 1)
  577. {
  578. master.WriteMultipleRegisters(slaveAddress, startAddress, value);
  579. }
  580. #endregion
  581. #region 单个数据读取
  582. /// <summary>
  583. /// 读取单个线圈
  584. /// </summary>
  585. /// <param name="startAddress"></param>
  586. /// <param name="slaveAddress"></param>
  587. /// <returns></returns>
  588. public bool ReadCoils(ushort startAddress, byte slaveAddress = 1)
  589. {
  590. var result = master.ReadCoils(slaveAddress, startAddress, 1);
  591. if (result == null) return false;
  592. if (result.Length == 1) return result[0];
  593. return false;
  594. //return master.ReadCoils(slaveAddress, startAddress, 1)[0];
  595. }
  596. /// <summary>
  597. /// 读取单个输入线圈
  598. /// </summary>
  599. /// <param name="startAddress"></param>
  600. /// <param name="slaveAddress"></param>
  601. /// <returns></returns>
  602. public bool ReadInputs(ushort startAddress, byte slaveAddress = 1)
  603. {
  604. var result = master.ReadInputs(slaveAddress, startAddress, 1);
  605. if (result == null) return false;
  606. if (result.Length == 1) return result[0];
  607. return false;
  608. //return master.ReadInputs(slaveAddress, startAddress, 1)[0];
  609. }
  610. /// <summary>
  611. /// 读取单个保持寄存器
  612. /// </summary>
  613. /// <param name="startAddress"></param>
  614. /// <param name="slaveAddress"></param>
  615. /// <returns></returns>
  616. public ushort ReadHoldingRegisters(ushort startAddress, byte slaveAddress = 1)
  617. {
  618. if (tcpClient == null) return 0;
  619. ushort[] result = null;
  620. try
  621. {
  622. result = master.ReadHoldingRegisters(slaveAddress, startAddress, 1);
  623. }
  624. catch (Exception ex)
  625. {
  626. ShowEx?.Invoke(ex.ToString());
  627. tcpClient = null;
  628. Connect();
  629. }
  630. if (result == null) return 0;
  631. if (result.Length == 1) return result[0];
  632. return 0;
  633. //return master.ReadHoldingRegisters(slaveAddress, startAddress, 1)[0];
  634. }
  635. /// <summary>
  636. /// 读取单个输入寄存器
  637. /// </summary>
  638. /// <param name="startAddress"></param>
  639. /// <param name="slaveAddress"></param>
  640. /// <returns></returns>
  641. public ushort ReadInputRegisters(ushort startAddress, byte slaveAddress = 1)
  642. {
  643. var result = master.ReadInputRegisters(slaveAddress, startAddress, 1);
  644. if (result == null) return 0;
  645. if (result.Length == 1) return result[0];
  646. return 0;
  647. //return master.ReadInputRegisters(slaveAddress, startAddress, 1)[0];
  648. }
  649. #endregion
  650. #region 单个数据写入
  651. /// <summary>
  652. /// 写入单个线圈
  653. /// </summary>
  654. /// <param name="startAddress"></param>
  655. /// <param name="value"></param>
  656. /// <param name="slaveAddress"></param>
  657. public void WriteSingleCoil(ushort startAddress, bool value, byte slaveAddress = 1)
  658. {
  659. master.WriteSingleCoil(slaveAddress, startAddress, value);
  660. }
  661. /// <summary>
  662. /// 写入单个寄存器
  663. /// </summary>
  664. /// <param name="startAddress"></param>
  665. /// <param name="value"></param>
  666. /// <param name="slaveAddress"></param>
  667. public void WriteSingleRegister(ushort startAddress, ushort value, byte slaveAddress = 1)
  668. {
  669. master.WriteSingleRegister(slaveAddress, startAddress, value);
  670. }
  671. #endregion
  672. }
  673. public enum CommandType
  674. {
  675. /// <summary>
  676. /// 线圈操作
  677. /// </summary>
  678. Coils,
  679. /// <summary>
  680. /// 输入线圈操作
  681. /// </summary>
  682. Inputs,
  683. /// <summary>
  684. /// 保持寄存器操作
  685. /// </summary>
  686. HoldingRegisters,
  687. /// <summary>
  688. /// 输入寄存器操作
  689. /// </summary>
  690. InputRegisters,
  691. }
  692. }