serial_reader.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. package uhf
  2. import (
  3. "errors"
  4. "github.com/tarm/serial"
  5. "io"
  6. "os"
  7. "sync"
  8. "sync/atomic"
  9. "time"
  10. )
  11. type SerialReader struct {
  12. COMPort string
  13. BaudRate int
  14. port *serial.Port
  15. connected atomic.Bool
  16. buffer []byte // 拼包缓冲区
  17. ioMu sync.Mutex
  18. }
  19. func NewSerialReader(comPort string, baudRate int) *SerialReader {
  20. return &SerialReader{
  21. COMPort: comPort,
  22. BaudRate: baudRate,
  23. }
  24. }
  25. func (s *SerialReader) Connect() error {
  26. s.ioMu.Lock()
  27. defer s.ioMu.Unlock()
  28. cfg := &serial.Config{
  29. Name: s.COMPort,
  30. Baud: s.BaudRate,
  31. ReadTimeout: 1 * time.Second,
  32. Size: 8,
  33. Parity: serial.ParityNone,
  34. StopBits: serial.Stop1,
  35. }
  36. port, err := serial.OpenPort(cfg)
  37. if err != nil {
  38. s.connected.Store(false)
  39. return err
  40. }
  41. s.port = port
  42. s.connected.Store(true)
  43. return nil
  44. }
  45. func (s *SerialReader) Disconnect() error {
  46. s.ioMu.Lock()
  47. defer s.ioMu.Unlock()
  48. if s.port != nil {
  49. _ = s.port.Close()
  50. }
  51. s.connected.Store(false)
  52. s.buffer = nil
  53. return nil
  54. }
  55. func (s *SerialReader) IsConnected() bool {
  56. return s.connected.Load()
  57. }
  58. func (s *SerialReader) SendData(data []byte) error {
  59. s.ioMu.Lock()
  60. defer s.ioMu.Unlock()
  61. return s.sendDataLocked(data)
  62. }
  63. func (s *SerialReader) sendDataLocked(data []byte) error {
  64. if !s.connected.Load() {
  65. return errors.New("串口未连接")
  66. }
  67. n, err := s.port.Write(data)
  68. if err != nil {
  69. return err
  70. }
  71. if n != len(data) {
  72. return errors.New("发送不完整")
  73. }
  74. return nil
  75. }
  76. // ==============================
  77. // 🔥 关键修复:串口按协议变长帧提取(标签帧25字节,继电器应答9字节等)
  78. // ==============================
  79. func (s *SerialReader) ReadData() ([]byte, error) {
  80. s.ioMu.Lock()
  81. defer s.ioMu.Unlock()
  82. return s.readDataLocked()
  83. }
  84. func (s *SerialReader) readDataLocked() ([]byte, error) {
  85. if !s.connected.Load() {
  86. return nil, errors.New("串口未连接")
  87. }
  88. buf := make([]byte, 1024)
  89. for {
  90. n, err := s.port.Read(buf)
  91. if err != nil {
  92. if err == io.EOF || os.IsTimeout(err) {
  93. break
  94. }
  95. s.connected.Store(false)
  96. return nil, err
  97. }
  98. if n == 0 {
  99. break
  100. }
  101. s.buffer = append(s.buffer, buf[:n]...)
  102. if frame, rest, ok := extractUHFFrame(s.buffer); ok {
  103. s.buffer = rest
  104. return frame, nil
  105. }
  106. }
  107. if len(s.buffer) > 0 {
  108. return nil, ErrIncompleteFrame
  109. }
  110. return nil, ErrReadTimeout
  111. }
  112. func (s *SerialReader) SendAndRecv(data []byte) ([]byte, error) {
  113. s.ioMu.Lock()
  114. defer s.ioMu.Unlock()
  115. if err := s.sendDataLocked(data); err != nil {
  116. return nil, err
  117. }
  118. time.Sleep(100 * time.Millisecond)
  119. return s.readDataLocked()
  120. }