You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

179 lines
3.1 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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()
}