package uhf import ( "errors" "github.com/tarm/serial" "io" "os" "sync" "sync/atomic" "time" ) type SerialReader struct { COMPort string BaudRate int port *serial.Port connected atomic.Bool buffer []byte // 拼包缓冲区 ioMu sync.Mutex } func NewSerialReader(comPort string, baudRate int) *SerialReader { return &SerialReader{ COMPort: comPort, BaudRate: baudRate, } } func (s *SerialReader) Connect() error { s.ioMu.Lock() defer s.ioMu.Unlock() cfg := &serial.Config{ Name: s.COMPort, Baud: s.BaudRate, ReadTimeout: 1 * time.Second, Size: 8, Parity: serial.ParityNone, StopBits: serial.Stop1, } port, err := serial.OpenPort(cfg) if err != nil { s.connected.Store(false) return err } s.port = port s.connected.Store(true) return nil } func (s *SerialReader) Disconnect() error { s.ioMu.Lock() defer s.ioMu.Unlock() if s.port != nil { _ = s.port.Close() } s.connected.Store(false) s.buffer = nil return nil } func (s *SerialReader) IsConnected() bool { return s.connected.Load() } func (s *SerialReader) SendData(data []byte) error { s.ioMu.Lock() defer s.ioMu.Unlock() return s.sendDataLocked(data) } func (s *SerialReader) sendDataLocked(data []byte) error { if !s.connected.Load() { return errors.New("串口未连接") } n, err := s.port.Write(data) if err != nil { return err } if n != len(data) { return errors.New("发送不完整") } return nil } // ============================== // 🔥 关键修复:串口按协议变长帧提取(标签帧25字节,继电器应答9字节等) // ============================== func (s *SerialReader) ReadData() ([]byte, error) { s.ioMu.Lock() defer s.ioMu.Unlock() return s.readDataLocked() } func (s *SerialReader) readDataLocked() ([]byte, error) { if !s.connected.Load() { return nil, errors.New("串口未连接") } buf := make([]byte, 1024) for { n, err := s.port.Read(buf) if err != nil { if err == io.EOF || os.IsTimeout(err) { break } s.connected.Store(false) return nil, err } if n == 0 { break } s.buffer = append(s.buffer, buf[:n]...) if frame, rest, ok := extractUHFFrame(s.buffer); ok { s.buffer = rest return frame, nil } } if len(s.buffer) > 0 { return nil, ErrIncompleteFrame } return nil, ErrReadTimeout } func (s *SerialReader) SendAndRecv(data []byte) ([]byte, error) { s.ioMu.Lock() defer s.ioMu.Unlock() if err := s.sendDataLocked(data); err != nil { return nil, err } time.Sleep(100 * time.Millisecond) return s.readDataLocked() }