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.

207 lines
6.7 KiB

  1. using System.Diagnostics;
  2. using System.IO.Ports;
  3. namespace UHFHelper
  4. {
  5. public class UHF_RS485_Helper
  6. {
  7. private SerialPort? _serialPort;
  8. private SerialParam? _serialParam;
  9. /// <summary>
  10. /// 单例模式
  11. /// </summary>
  12. private static UHF_RS485_Helper? Instance { get; set; }
  13. public static UHF_RS485_Helper GetInstance()
  14. {
  15. if (Instance == null)
  16. {
  17. Instance = new UHF_RS485_Helper();
  18. }
  19. return Instance;
  20. }
  21. /// <summary>
  22. /// 打开串口
  23. /// </summary>
  24. /// <param name="param"></param>
  25. public void Open(SerialParam param)
  26. {
  27. _serialParam = param;
  28. _serialPort = new SerialPort(_serialParam.PortName, _serialParam.BaudRate, _serialParam.PortParity, _serialParam.DataBits);
  29. _serialPort.Open();
  30. }
  31. /// <summary>
  32. /// 获取串口状态
  33. /// </summary>
  34. /// <returns></returns>
  35. public bool GetSerialPortState()
  36. {
  37. if (_serialPort!=null)
  38. {
  39. return _serialPort.IsOpen;
  40. }
  41. else
  42. {
  43. return false;
  44. }
  45. }
  46. /// <summary>
  47. /// 关闭串口
  48. /// </summary>
  49. public void Close()
  50. {
  51. if (_serialPort == null) return;
  52. _serialPort.Close();
  53. _serialPort.Dispose();
  54. _serialPort = null;
  55. }
  56. /// <summary>
  57. /// 读卡方法,返回读卡器数据
  58. /// </summary>
  59. /// <param name="adr">设备读取地址</param>
  60. /// <returns></returns>
  61. public async Task<DKoutput?> ReadCard(int adr)
  62. {
  63. DKoutput dKoutput = new();
  64. var readByte = ReadByte(adr);
  65. var result = await SendMessageAsync(readByte, TimeSpan.FromSeconds(1), 18);
  66. if (result == null)
  67. {
  68. return null;
  69. }
  70. else
  71. {
  72. //获取校验码
  73. var crc = result.Skip(16).Take(2).ToArray();
  74. //获取卡号
  75. var cardNo = result.Skip(6).Take(10).ToArray();
  76. //获取读卡器数据
  77. var readData = result.Skip(0).Take(16).ToArray();
  78. //获取读卡器地址
  79. var address = result.Skip(1).Take(1).ToArray();
  80. //判断数据是否合法
  81. var temcrc = CRC16.ToCRC16(readData);
  82. if (crc.ByteArrayToHexString() == temcrc.ByteArrayToHexString())
  83. {
  84. dKoutput.Address = address.ByteArrayToHexString();
  85. dKoutput.ResData = cardNo.ByteArrayToHexString();
  86. return dKoutput;
  87. }
  88. else
  89. {
  90. return null;
  91. }
  92. }
  93. }
  94. /// <summary>
  95. /// 生成读取命令
  96. /// </summary>
  97. /// <returns></returns>
  98. private byte[] ReadByte(int adr)
  99. {
  100. //根据读取地址生成读取命令
  101. byte[] data1 = new byte[3] { 04, (byte)adr, 01 };
  102. //生成crc校验码
  103. byte[] data2 = CRC16.ToCRC16(data1);
  104. byte[] data3 = new byte[data1.Length + data2.Length];
  105. data1.CopyTo(data3, 0);
  106. data2.CopyTo(data3, data1.Length);
  107. return data3;
  108. }
  109. /// <summary>
  110. /// 获取本机可用串口
  111. /// </summary>
  112. /// <returns></returns>
  113. public string[] GetLocalSerialPortNames()
  114. {
  115. return SerialPort.GetPortNames();
  116. }
  117. /// <summary>
  118. /// 发送数据
  119. /// </summary>
  120. /// <param name="msg">数据</param>
  121. /// <param name="timeout">超时时间</param>
  122. /// <param name="count">串口回复字节数</param>
  123. /// <returns></returns>
  124. public byte[]? SendMessage(byte[] msg, TimeSpan timeout, int count)
  125. {
  126. if (_serialPort == null) return null;
  127. var stopwatch = Stopwatch.StartNew();
  128. var originalWriteTimeout = _serialPort.WriteTimeout;
  129. var originalReadTimeout = _serialPort.ReadTimeout;
  130. try
  131. {
  132. _serialPort.WriteTimeout = (int)Math.Max((timeout - stopwatch.Elapsed).TotalMilliseconds, 0);
  133. _serialPort.Write(msg, 0, msg.Length);
  134. var tmpCount = count;
  135. byte[] buffer = new byte[tmpCount];
  136. int offset = 0;
  137. while (tmpCount > 0)
  138. {
  139. _serialPort.ReadTimeout = (int)Math.Max((timeout - stopwatch.Elapsed).TotalMilliseconds, 0);
  140. var readCount = _serialPort.Read(buffer, offset, tmpCount);
  141. if (readCount==6)
  142. {
  143. tmpCount = 0;
  144. continue;
  145. }
  146. offset += readCount;
  147. tmpCount -= readCount;
  148. }
  149. _serialPort.DiscardInBuffer();
  150. return buffer;
  151. }catch(Exception ex)
  152. {
  153. return null;
  154. }
  155. finally
  156. {
  157. _serialPort.ReadTimeout = originalReadTimeout;
  158. _serialPort.WriteTimeout = originalWriteTimeout;
  159. }
  160. }
  161. /// <summary>
  162. /// 发送数据
  163. /// </summary>
  164. /// <param name="msg">数据</param>
  165. /// <param name="timeout">超时时间</param>
  166. /// <param name="count">串口回复字节数</param>
  167. /// <returns></returns>
  168. public async Task<byte[]?> SendMessageAsync(byte[] msg, TimeSpan timeout, int count)
  169. {
  170. var sendTask = Task.Run(() => SendMessage(msg, timeout, count));
  171. try
  172. {
  173. await Task.WhenAny(sendTask, Task.Delay(timeout));
  174. }
  175. catch (TaskCanceledException)
  176. {
  177. throw new TimeoutException();
  178. }
  179. return await sendTask;
  180. }
  181. /// <summary>
  182. /// 发出蜂鸣声音3次,代表扣款成功!
  183. /// </summary>
  184. public async void OpenBeep(int addr)
  185. {
  186. byte[] sendData = new byte[]{ 0x07, (byte)addr, 0x33, 0x08, 0x02, 0x03, 0x33,0xB1 };
  187. await SendMessageAsync(sendData, TimeSpan.FromSeconds(1), 6);
  188. }
  189. }
  190. public class SerialParam
  191. {
  192. public string PortName { get; set; } = "COM3";
  193. public int BaudRate { get; set; } = 57600;
  194. public int DataBits { get; set; } = 8;
  195. public Parity PortParity { get; set; } = Parity.None;
  196. public StopBits PortStopBits { get; set; } = StopBits.One;
  197. }
  198. }