serial_reader.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. package uhf
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/tarm/serial"
  6. "io"
  7. "os"
  8. "time"
  9. )
  10. type SerialReader struct {
  11. COMPort string
  12. BaudRate int
  13. port *serial.Port
  14. isConnected bool
  15. readBufSize int
  16. }
  17. // 初始化串口
  18. func NewSerialReader(comPort string, baudRate int) *SerialReader {
  19. return &SerialReader{
  20. COMPort: comPort,
  21. BaudRate: baudRate,
  22. readBufSize: 1024, // 足够容纳设备响应
  23. }
  24. }
  25. // Connect 建立串口连接(显式配置8数据位,和工具一致)
  26. func (s *SerialReader) Connect() error {
  27. cfg := &serial.Config{
  28. Name: s.COMPort,
  29. Baud: s.BaudRate,
  30. ReadTimeout: 1 * time.Second, // 读超时1秒,核心超时配置
  31. Size: 8, // 8位数据位(必须显式配置!)
  32. Parity: serial.ParityNone,
  33. StopBits: serial.Stop1,
  34. }
  35. port, err := serial.OpenPort(cfg)
  36. if err != nil {
  37. s.isConnected = false
  38. return fmt.Errorf("打开串口失败: %v", err)
  39. }
  40. s.port = port
  41. s.isConnected = true
  42. return nil
  43. }
  44. // Disconnect 断开连接
  45. func (s *SerialReader) Disconnect() error {
  46. if s.port != nil {
  47. err := s.port.Close()
  48. s.isConnected = false
  49. return err
  50. }
  51. return nil
  52. }
  53. // IsConnected 检查状态
  54. func (s *SerialReader) IsConnected() bool {
  55. return s.isConnected
  56. }
  57. // SendData 发送串口数据(移除无效的Flush断言,保留核心发送逻辑)
  58. func (s *SerialReader) SendData(data []byte) error {
  59. if !s.isConnected {
  60. return errors.New("串口连接未建立")
  61. }
  62. // 完整写入所有字节
  63. n, err := s.port.Write(data)
  64. if err != nil {
  65. return fmt.Errorf("发送数据失败: %v", err)
  66. }
  67. // 校验是否发送完整(核心:确保指令全部发出)
  68. if n != len(data) {
  69. return fmt.Errorf("发送字节数不完整,发送%d/预期%d", n, len(data))
  70. }
  71. // ✅ 移除无效的Flush断言(tarm/serial的Port无此方法)
  72. // 注:tarm/serial的Write本身会立即写入串口,无需手动Flush
  73. return nil
  74. }
  75. // ReadData 循环读取串口数据(无SetReadDeadline,依赖ReadTimeout)
  76. func (s *SerialReader) ReadData() ([]byte, error) {
  77. if !s.isConnected {
  78. return nil, errors.New("串口连接未建立")
  79. }
  80. buf := make([]byte, s.readBufSize)
  81. var resp []byte
  82. // 循环读取,直到超时/拿到完整响应
  83. for {
  84. n, err := s.port.Read(buf)
  85. if err != nil {
  86. // 超时/EOF是正常结束(ReadTimeout触发)
  87. if err == io.EOF || os.IsTimeout(err) {
  88. break
  89. }
  90. s.isConnected = false
  91. return nil, fmt.Errorf("读取数据失败: %v", err)
  92. }
  93. if n > 0 {
  94. resp = append(resp, buf[:n]...)
  95. // 检测到完整响应(帧头0xCF+最小长度7),提前退出
  96. if len(resp) >= 7 && resp[0] == 0xCF {
  97. break
  98. }
  99. }
  100. }
  101. return resp, nil
  102. }
  103. // SendAndRecv 串口发送并等待响应(增加发送后延迟,核心优化)
  104. func (s *SerialReader) SendAndRecv(data []byte) ([]byte, error) {
  105. if err := s.SendData(data); err != nil {
  106. return nil, err
  107. }
  108. // 发送后延迟100ms,给设备处理指令的时间(工具也有此隐性延迟)
  109. time.Sleep(100 * time.Millisecond)
  110. // 读取响应
  111. return s.ReadData()
  112. }