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