155 lines
2.9 KiB
Go
155 lines
2.9 KiB
Go
package camera
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/zeromicro/go-zero/core/logx"
|
|
)
|
|
|
|
// 命令常量
|
|
const (
|
|
CmdTakePhoto = "T1"
|
|
CmdGetDetectionResult = "GM,2,0"
|
|
)
|
|
|
|
type Client struct {
|
|
addr string
|
|
conn net.Conn
|
|
timeout time.Duration
|
|
mu sync.Mutex
|
|
}
|
|
|
|
func NewClient(addr string, timeout ...time.Duration) *Client {
|
|
t := 1 * time.Second
|
|
if len(timeout) > 0 {
|
|
t = timeout[0]
|
|
}
|
|
return &Client{
|
|
addr: addr,
|
|
timeout: t,
|
|
}
|
|
}
|
|
|
|
func (c *Client) Connect() error {
|
|
logx.Infof("正在连接相机: %s", c.addr)
|
|
conn, err := net.DialTimeout("tcp", c.addr, c.timeout)
|
|
if err != nil {
|
|
logx.Errorf("相机连接失败: %v", err)
|
|
return fmt.Errorf("相机连接失败: %w", err)
|
|
}
|
|
c.conn = conn
|
|
logx.Infof("相机连接成功: %s", c.addr)
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) ConnectWithRetry(maxRetries int, retryInterval time.Duration) error {
|
|
var err error
|
|
for i := 0; i < maxRetries; i++ {
|
|
err = c.Connect()
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
logx.Errorf("连接失败,%v后重试...", retryInterval)
|
|
time.Sleep(retryInterval)
|
|
}
|
|
return fmt.Errorf("连接相机失败: %w", err)
|
|
}
|
|
|
|
func (c *Client) IsConnected() bool {
|
|
return c.conn != nil
|
|
}
|
|
|
|
func (c *Client) Reconnect() error {
|
|
c.Close()
|
|
return c.Connect()
|
|
}
|
|
|
|
func (c *Client) SendCommand(cmd string) ([]byte, error) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
if c.conn == nil {
|
|
return nil, fmt.Errorf("未建立连接")
|
|
}
|
|
|
|
logx.Infof("发送相机指令: %s", cmd)
|
|
_, err := c.conn.Write([]byte(cmd + "\r"))
|
|
if err != nil {
|
|
logx.Errorf("发送指令失败: %v", err)
|
|
return nil, fmt.Errorf("发送指令失败: %w", err)
|
|
}
|
|
resp, err := c.readResponse()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
logx.Infof("收到相机响应: %s", string(resp))
|
|
return resp, nil
|
|
}
|
|
|
|
func (c *Client) readResponse() ([]byte, error) {
|
|
reader := bufio.NewReader(c.conn)
|
|
var buffer bytes.Buffer
|
|
|
|
if err := c.conn.SetReadDeadline(time.Now().Add(c.timeout)); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for {
|
|
b, err := reader.ReadByte()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
buffer.WriteByte(b)
|
|
if b == '\r' || b == '\n' {
|
|
break
|
|
}
|
|
}
|
|
return buffer.Bytes(), nil
|
|
}
|
|
|
|
func (c *Client) SendCommandWithContext(ctx context.Context, cmd string) ([]byte, error) {
|
|
type result struct {
|
|
resp []byte
|
|
err error
|
|
}
|
|
ch := make(chan result, 1)
|
|
|
|
go func() {
|
|
resp, err := c.SendCommand(cmd)
|
|
ch <- result{resp, err}
|
|
}()
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return nil, ctx.Err()
|
|
case res := <-ch:
|
|
return res.resp, res.err
|
|
}
|
|
}
|
|
|
|
func (c *Client) TakePhoto() error {
|
|
_, err := c.SendCommand(CmdTakePhoto)
|
|
return err
|
|
}
|
|
|
|
func (c *Client) GetDetectionResult() (string, error) {
|
|
resp, err := c.SendCommand(CmdGetDetectionResult)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(resp), nil
|
|
}
|
|
func (c *Client) Close() {
|
|
if c.conn != nil {
|
|
c.conn.Close()
|
|
c.conn = nil
|
|
logx.Infof("相机连接已关闭")
|
|
}
|
|
}
|