SerialManager.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. using System;
  2. using System.IO.Ports; // 添加必要的命名空间
  3. using System.Text;
  4. using System.Text.RegularExpressions;
  5. using System.Windows.Forms; // 用于BeginInvoke调用
  6. namespace Bird_tool
  7. {
  8. class SerialManager
  9. {
  10. public delegate void LogHandler(string message, LogLevel level);
  11. public delegate void LogShowHandler(string message);
  12. public event LogHandler OnLog;
  13. public delegate void DisconnectHandler(bool isError);
  14. public delegate void ConnectHandler();
  15. public event DisconnectHandler OnDisconnect;
  16. public event ConnectHandler OnConnect;
  17. private SerialPort _uart = new SerialPort();
  18. private int MAX_BUFFER_SIZE = 4096; // 最大缓冲区大小
  19. // 定义行数据接收事件
  20. public event Action<string> OnLineReceived;
  21. public string _tmp_text = ""; // 暂存串口返回的数据
  22. public Regex reg_R = new Regex(@"\r"); // 匹配/r回车符
  23. public Regex reg_N = new Regex(@"\n"); // 匹配/n换行符
  24. public Regex reg_RN = new Regex(@"\r\n"); // 匹配标准换行符
  25. public void Config(int dataBits = 8, StopBits stopBits = StopBits.One, Parity parity = Parity.None)
  26. {
  27. _uart.DataBits = dataBits; // 数据位
  28. _uart.StopBits = stopBits; // 停止位
  29. _uart.Parity = parity; // 校验位
  30. }
  31. public void SetMaxBuffer(int buffer_size)
  32. {
  33. MAX_BUFFER_SIZE = buffer_size;
  34. }
  35. public bool Connect(string portName, int baudRate = 115200)
  36. {
  37. if (_uart.IsOpen)
  38. {
  39. OnLog?.Invoke("串口已经打开", LogLevel.debug);
  40. return true;
  41. }
  42. _uart.PortName = portName;
  43. _uart.BaudRate = baudRate;
  44. _uart.Encoding = Encoding.ASCII;
  45. _uart.DataReceived += CommDataReceived;
  46. try
  47. {
  48. _uart.Open();
  49. System.Threading.Thread.Sleep(150);
  50. OnConnect?.Invoke();
  51. return true;
  52. }
  53. catch (Exception ex)
  54. {
  55. ErrorHandle("串口打开失败", ex);
  56. return false;
  57. }
  58. }
  59. public void Disconnect(bool isError = false)
  60. {
  61. if (_uart.IsOpen)
  62. {
  63. _uart.DataReceived -= CommDataReceived;
  64. _uart.Close();
  65. OnDisconnect?.Invoke(isError);
  66. }
  67. _tmp_text = ""; // 清空缓冲区
  68. }
  69. public bool ReOpen()
  70. {
  71. return Connect(_uart.PortName, _uart.BaudRate);
  72. }
  73. public bool IsOpen ()
  74. {
  75. return _uart.IsOpen;
  76. }
  77. private void CommDataReceived(object sender, SerialDataReceivedEventArgs e)
  78. {
  79. try
  80. {
  81. int bytesToRead = _uart.BytesToRead;
  82. byte[] buffer = new byte[bytesToRead];
  83. _uart.Read(buffer, 0, bytesToRead);
  84. string receivedText = Encoding.ASCII.GetString(buffer);
  85. // 使用委托更新UI线程
  86. if (System.Windows.Forms.Application.OpenForms.Count > 0)
  87. {
  88. var mainForm = System.Windows.Forms.Application.OpenForms[0];
  89. mainForm.BeginInvoke((MethodInvoker)delegate {
  90. ProcessReceivedData(receivedText);
  91. });
  92. }
  93. else
  94. {
  95. // 非UI环境直接处理
  96. ProcessReceivedData(receivedText);
  97. }
  98. }
  99. catch (InvalidOperationException ex)
  100. {
  101. // 专门捕获串口断开异常
  102. ErrorHandle($"串口异常断开: {ex.Message}", ex);
  103. Disconnect(true); // 确保资源清理
  104. }
  105. catch (Exception ex)
  106. {
  107. ErrorHandle("串口接收异常", ex);
  108. if (ex is InvalidOperationException || ex is System.IO.IOException)
  109. {
  110. ErrorHandle($"串口意外断开: {ex.Message}", ex);
  111. Disconnect(true); // 确保资源清理
  112. }
  113. }
  114. }
  115. private void ProcessReceivedData(string newData)
  116. {
  117. _tmp_text += newData;
  118. // 缓冲区溢出保护
  119. if (_tmp_text.Length > MAX_BUFFER_SIZE)
  120. {
  121. ParseText(_tmp_text.Substring(0, MAX_BUFFER_SIZE));
  122. _tmp_text = _tmp_text.Substring(MAX_BUFFER_SIZE);
  123. }
  124. // 处理所有可能的换行符组合
  125. while (true)
  126. {
  127. int rnIndex = _tmp_text.IndexOf("\r\n");
  128. int rIndex = _tmp_text.IndexOf('\r');
  129. int nIndex = _tmp_text.IndexOf('\n');
  130. int splitIndex = -1;
  131. int splitLength = 0;
  132. if (rnIndex >= 0)
  133. {
  134. splitIndex = rnIndex;
  135. splitLength = 2;
  136. }
  137. else if (rIndex >= 0 && (rIndex < nIndex || nIndex < 0))
  138. {
  139. splitIndex = rIndex;
  140. splitLength = 1;
  141. }
  142. else if (nIndex >= 0)
  143. {
  144. splitIndex = nIndex;
  145. splitLength = 1;
  146. }
  147. if (splitIndex < 0) break;
  148. string line = _tmp_text.Substring(0, splitIndex);
  149. _tmp_text = _tmp_text.Substring(splitIndex + splitLength);
  150. if (!string.IsNullOrWhiteSpace(line))
  151. {
  152. ParseText(line);
  153. }
  154. }
  155. }
  156. private void ParseText(string line)
  157. {
  158. // 调用外部注册的事件处理器
  159. OnLineReceived?.Invoke(line);
  160. }
  161. public void SendCommand(string command)
  162. {
  163. if (_uart.IsOpen)
  164. {
  165. try
  166. {
  167. _uart.WriteLine(command);
  168. }
  169. catch (Exception ex)
  170. {
  171. ErrorHandle("发送命令失败", ex);
  172. }
  173. }
  174. }
  175. private void ErrorHandle(string tips, Exception ex)
  176. {
  177. // 确保日志系统存在或替换为您的实际实现
  178. bird_tool.Log_show($"{tips} {ex.Message}");
  179. bird_tool.Log($"{tips} {ex.Message}");
  180. Console.WriteLine($"{tips}: {ex.Message}");
  181. }
  182. }
  183. }