package client import ( "context" "io" "sync" "time" "github.com/noahlann/nnet/pkg/client" "go.bug.st/serial" ) // serialClient 串口客户端实现 type serialClient struct { config *client.Config port serial.Port mu sync.RWMutex connected bool ctx context.Context cancel context.CancelFunc readBuffer []byte } // NewSerialClient 创建串口客户端 func NewSerialClient(config *client.Config) client.Client { if config == nil { config = client.DefaultConfig() } ctx, cancel := context.WithCancel(context.Background()) c := &serialClient{ config: config, ctx: ctx, cancel: cancel, readBuffer: make([]byte, 4096), } return c } // Connect 连接串口 func (c *serialClient) Connect() error { c.mu.Lock() defer c.mu.Unlock() if c.connected { return nil } // 解析串口地址 addr := c.config.Addr if len(addr) >= 8 && addr[:8] == "serial://" { addr = addr[8:] } else if len(addr) >= 7 && addr[:7] == "serial:" { addr = addr[7:] } // 获取串口配置(简化处理,使用默认配置) // 注意:客户端配置中没有SerialConfig,这里使用默认配置 // 如果需要,可以在client.Config中添加SerialConfig字段 mode := &serial.Mode{ BaudRate: 9600, DataBits: 8, StopBits: serial.OneStopBit, Parity: serial.NoParity, } // 打开串口 port, err := serial.Open(addr, mode) if err != nil { return err } c.port = port c.connected = true return nil } // Disconnect 断开连接 func (c *serialClient) Disconnect() error { c.mu.Lock() defer c.mu.Unlock() if !c.connected { return nil } if c.port != nil { if err := c.port.Close(); err != nil { return err } c.port = nil } c.connected = false return nil } // Send 发送数据 func (c *serialClient) Send(data []byte) error { c.mu.RLock() defer c.mu.RUnlock() if !c.connected || c.port == nil { return io.ErrClosedPipe } _, err := c.port.Write(data) return err } // Receive 接收数据 func (c *serialClient) Receive() ([]byte, error) { c.mu.RLock() defer c.mu.RUnlock() if !c.connected || c.port == nil { return nil, io.ErrClosedPipe } n, err := c.port.Read(c.readBuffer) if err != nil { if err == io.EOF { return nil, nil } return nil, err } if n == 0 { return nil, nil } data := make([]byte, n) copy(data, c.readBuffer[:n]) return data, nil } // Request 请求-响应(带超时) func (c *serialClient) Request(data []byte, timeout time.Duration) ([]byte, error) { if err := c.Send(data); err != nil { return nil, err } ctx, cancel := context.WithTimeout(c.ctx, timeout) defer cancel() for { select { case <-ctx.Done(): return nil, ctx.Err() default: response, err := c.Receive() if err != nil { return nil, err } if len(response) > 0 { return response, nil } time.Sleep(10 * time.Millisecond) } } } // IsConnected 检查是否已连接 func (c *serialClient) IsConnected() bool { c.mu.RLock() defer c.mu.RUnlock() return c.connected } // Close 关闭客户端 func (c *serialClient) Close() error { c.cancel() return c.Disconnect() }