RS485Comm.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. ///**********************************************************
  2. ///RJCP.IO.Ports 可以跨平台,同样System.Ports也同样可以使用
  3. ///**********************************************************
  4. using System;
  5. using RJCP.IO.Ports;
  6. using System.Threading;
  7. using SHJX.Service.Common.Logging;
  8. using Microsoft.Extensions.Logging;
  9. namespace SHJX.Service.ServerClient.RS485
  10. {
  11. public static class Rs485Client
  12. {
  13. private static readonly ILogger logger = LogFactory.BuildLogger(typeof(Rs485Client));
  14. /// <summary>
  15. /// RS485通信对象
  16. /// </summary>
  17. public static SerialPortStream Sport { get; set; }
  18. /// <summary>
  19. /// 发送命令时锁定
  20. /// </summary>
  21. private static readonly object SnedLocker = new();
  22. /// <summary>
  23. /// 延时等待的单位间隔,默认20ms
  24. /// </summary>
  25. private static int DelayUnit { get; set; }
  26. /// <summary>
  27. /// 超时时长,默认1000ms
  28. /// </summary>
  29. private static int Timeout { get; set; }
  30. /// <summary>
  31. /// 端口状态:
  32. /// True=打开,False=关闭
  33. /// </summary>
  34. public static bool IsValid => Sport is not null && Sport.IsOpen;
  35. /// <summary>
  36. /// 初始化
  37. /// </summary>
  38. public static void InitPort()
  39. {
  40. // 创建COM通信对象
  41. Sport ??= new SerialPortStream
  42. {
  43. BaudRate = 9600,
  44. DataBits = 8,
  45. StopBits = StopBits.One,
  46. Parity = Parity.None
  47. };
  48. DelayUnit = 10;
  49. Timeout = 1000;
  50. }
  51. /// <summary>
  52. /// 打开COM通信端口,使用指定参数
  53. /// </summary>
  54. /// <param name="portName">端口号</param>
  55. /// <returns>是否正常打开</returns>
  56. public static bool Open(string portName)
  57. {
  58. try
  59. {
  60. lock (SnedLocker)
  61. {
  62. if (Sport.IsOpen) Sport.Close();
  63. Sport.PortName = portName;
  64. try
  65. {
  66. Sport.Open();
  67. }
  68. catch (Exception ex)
  69. {
  70. logger?.LogError(ex.Message);
  71. }
  72. }
  73. return Sport.IsOpen;
  74. }
  75. catch (UnauthorizedAccessException exIo)
  76. {
  77. logger?.LogError(exIo.ToString());
  78. return false;
  79. }
  80. catch (Exception ex)
  81. {
  82. logger?.LogError(ex.ToString());
  83. return false;
  84. }
  85. }
  86. /// <summary>
  87. /// 关闭COM通信端口
  88. /// </summary>
  89. /// <returns>true=已关闭,false=未关闭</returns>
  90. public static void Close()
  91. {
  92. //var open = Sport.IsOpen;
  93. if (!Sport.IsOpen) return;
  94. Sport.Close();
  95. //Sport.Dispose();
  96. }
  97. /// <summary>
  98. /// 向端口发送指令,并等待回复。
  99. /// 以lastChar字符作为回复的结尾识别字符,收到该字符后返回。
  100. /// 失败时,返回string.Empty
  101. /// </summary>
  102. /// <param name="cmdStr">指令</param>
  103. /// <param name="lastChar">结尾识别字符</param>
  104. /// <returns>完整的应答数据,含结尾识别字符</returns>
  105. public static string SendData(string cmdStr, char lastChar)
  106. {
  107. if (Sport.IsOpen.Equals(false)) return string.Empty;
  108. lock (SnedLocker)
  109. {
  110. for (; ; )
  111. {
  112. try
  113. {
  114. var strRes = string.Empty;
  115. Sport.DiscardInBuffer();
  116. Sport.DiscardOutBuffer();
  117. Sport.Write(cmdStr);// 发送指令
  118. // 等待回复
  119. for (var i = 0; i < Timeout / DelayUnit; i++)
  120. {
  121. // 判断数据是否接收完整
  122. if (Sport.BytesToRead > 0)
  123. strRes += Sport.ReadExisting();
  124. if (strRes.IndexOf(lastChar) != -1)
  125. break;
  126. Thread.Sleep(DelayUnit);
  127. }
  128. if (strRes.Length.Equals(0))
  129. {
  130. strRes = string.Empty;
  131. }
  132. return strRes;
  133. }
  134. catch (UnauthorizedAccessException exIo)
  135. {
  136. logger?.LogError(exIo.ToString());
  137. }
  138. catch (Exception ex)
  139. {
  140. logger?.LogError(ex.ToString());
  141. }
  142. }
  143. }
  144. }
  145. /// <summary>
  146. /// 向端口发送指令,并等待回复。
  147. /// 以lastStr字符串作为回复的结尾识别字符,收到该字符串后返回。
  148. /// 失败时,返回string.Empty
  149. /// </summary>
  150. /// <param name="cmdStr">指令</param>
  151. /// <param name="lastStr"></param>
  152. /// <returns>收到的回复数据,含结尾识别字符串</returns>
  153. public static string SendData(string cmdStr, string lastStr)
  154. {
  155. if (Sport.IsOpen == false)
  156. return string.Empty;
  157. lock (SnedLocker)
  158. {
  159. for (; ; )
  160. {
  161. try
  162. {
  163. var strRes = string.Empty;
  164. Sport.DiscardInBuffer();
  165. Sport.DiscardOutBuffer();
  166. Sport.Write(cmdStr);// 发送指令
  167. // 等待回复
  168. for (var i = 0; i < Timeout / DelayUnit; i++)
  169. {
  170. // 判断数据是否接收完整
  171. if (Sport.BytesToRead > 0)
  172. {
  173. strRes += Sport.ReadExisting();
  174. }
  175. if (strRes.IndexOf(lastStr, StringComparison.Ordinal) > 0)
  176. {
  177. break;
  178. }
  179. Thread.Sleep(DelayUnit);
  180. }
  181. if (strRes.Length == 0)
  182. {
  183. strRes = string.Empty;
  184. }
  185. return strRes;
  186. }
  187. catch (UnauthorizedAccessException exIo)
  188. {
  189. logger?.LogError(exIo.ToString());
  190. }
  191. catch (Exception ex)
  192. {
  193. logger?.LogError(ex.ToString());
  194. }
  195. }
  196. }
  197. }
  198. }
  199. }