273 lines
5.8 KiB
Go
273 lines
5.8 KiB
Go
/*
|
|||
|
|
* Copyright (c) 2025 Beijing Hardman Automation Equipment Co., LTD. All rights reserved.
|
||
|
|
*
|
||
|
|
* Project: adapter
|
||
|
|
* File: common.go
|
||
|
|
* Last: 2025-05-15 10:57:25
|
||
|
|
* Author: wangcheng@bj-hardman.com
|
||
|
|
*/
|
||
|
|
|
||
|
|
package robot
|
||
|
|
|
||
|
|
import (
|
||
|
|
"bytes"
|
||
|
|
"context"
|
||
|
|
"encoding/binary"
|
||
|
|
"log/slog"
|
||
|
|
"sync"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"bj_power_mes/constants"
|
||
|
|
"bj_power_mes/internal/plc"
|
||
|
|
"bj_power_mes/internal/preload"
|
||
|
|
)
|
||
|
|
|
||
|
|
type arg struct {
|
||
|
|
name string
|
||
|
|
value any
|
||
|
|
}
|
||
|
|
|
||
|
|
func newArg(value any, name ...string) arg {
|
||
|
|
if len(name) > 0 {
|
||
|
|
return arg{
|
||
|
|
name: name[0],
|
||
|
|
value: value,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return arg{
|
||
|
|
value: value,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (c *Controller) executeAction(ctx context.Context, action string, args ...arg) error {
|
||
|
|
addr := preload.GetMAddress(action)
|
||
|
|
return c.execute(ctx, addr, args, true)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (c *Controller) execute(ctx context.Context, addr preload.MAddress, args []arg, autoClear bool) error {
|
||
|
|
c.mtx.Lock()
|
||
|
|
defer c.mtx.Unlock()
|
||
|
|
|
||
|
|
select {
|
||
|
|
case <-ctx.Done():
|
||
|
|
return ctx.Err()
|
||
|
|
default:
|
||
|
|
if err := c.sendSignal(addr, args...); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return c.waitReply(ctx, addr, autoClear)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (c *Controller) sendSignal(addr preload.MAddress, args ...arg) error {
|
||
|
|
buf := new(bytes.Buffer)
|
||
|
|
//buf.WriteByte(1)
|
||
|
|
for _, a := range args {
|
||
|
|
_ = binary.Write(buf, binary.BigEndian, a.value)
|
||
|
|
}
|
||
|
|
|
||
|
|
//先写参数
|
||
|
|
err := c.plcClient.Write(addr.Addr.Add(1, 0).String(), buf.Bytes())
|
||
|
|
if err != nil {
|
||
|
|
slog.Error("写入PLC信号失败",
|
||
|
|
slog.Any("address", addr),
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
time.Sleep(time.Millisecond * 200)
|
||
|
|
//再写信号
|
||
|
|
err = c.plcClient.WriteByte(addr.Address(), 1)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
attrCount := 0
|
||
|
|
for _, a := range args {
|
||
|
|
if a.name != "" {
|
||
|
|
attrCount++
|
||
|
|
}
|
||
|
|
}
|
||
|
|
attrs := make([]any, 0, attrCount)
|
||
|
|
for _, a := range args {
|
||
|
|
if a.name == "" {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
attrs = append(attrs, slog.Any(a.name, a.value))
|
||
|
|
}
|
||
|
|
|
||
|
|
slog.Info("已发送PLC信号",
|
||
|
|
slog.Any("address", addr),
|
||
|
|
slog.Group("params", attrs...), // 使用Group包装属性
|
||
|
|
)
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (c *Controller) SendSignalOnly(addr preload.MAddress) error {
|
||
|
|
err := c.plcClient.WriteByte(addr.Address(), 1)
|
||
|
|
if err != nil {
|
||
|
|
slog.Error("写入PLC信号失败",
|
||
|
|
slog.Any("address", addr),
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
slog.Info("已发送PLC信号",
|
||
|
|
slog.Any("address", addr),
|
||
|
|
)
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (c *Controller) WaitSignal(ctx context.Context, addr preload.MAddress, value bool, offsetAddress bool) error {
|
||
|
|
replayAddr := addr.Addr.Add(0, 0)
|
||
|
|
if offsetAddress {
|
||
|
|
replayAddr = addr.Addr.Add(9, 0)
|
||
|
|
}
|
||
|
|
t := time.NewTicker(c.checkSignalDuration)
|
||
|
|
defer t.Stop()
|
||
|
|
|
||
|
|
once := sync.Once{}
|
||
|
|
retryCount := 0
|
||
|
|
for {
|
||
|
|
select {
|
||
|
|
case <-ctx.Done():
|
||
|
|
return ctx.Err()
|
||
|
|
case <-t.C:
|
||
|
|
result, err := c.plcClient.ReadBool(replayAddr.String())
|
||
|
|
if err != nil {
|
||
|
|
slog.Error("读取PLC信号失败",
|
||
|
|
slog.String("address", replayAddr.String()),
|
||
|
|
slog.Int("retry", retryCount),
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
retryCount++
|
||
|
|
if retryCount >= c.maxRetries {
|
||
|
|
slog.Error("读取PLC完成信号失败",
|
||
|
|
slog.Any("address", replayAddr),
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
if result == value {
|
||
|
|
slog.Info("收到PLC完成信号",
|
||
|
|
slog.Any("address", replayAddr),
|
||
|
|
)
|
||
|
|
return nil
|
||
|
|
} else {
|
||
|
|
if alarmSvc := c.alarmSvc; alarmSvc != nil {
|
||
|
|
err = c.GetErrorCode()
|
||
|
|
if err != nil {
|
||
|
|
once.Do(func() {
|
||
|
|
slog.Error("PLC Error", slog.Any("error", err))
|
||
|
|
alarmSvc.Raise(ctx,
|
||
|
|
"ROBOT_ERROR",
|
||
|
|
err.Error(),
|
||
|
|
constants.AlarmLevel_ERROR,
|
||
|
|
0, 0,
|
||
|
|
"robot",
|
||
|
|
)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (c *Controller) WaitSignal_TwoSignals(ctx context.Context, addr preload.MAddress, value bool, offsetAddress bool, addrResult preload.MAddress, valueResult bool) (bool, error) {
|
||
|
|
replayAddr := addr.Addr.Add(0, 0)
|
||
|
|
if offsetAddress {
|
||
|
|
replayAddr = addr.Addr.Add(9, 0)
|
||
|
|
}
|
||
|
|
t := time.NewTicker(c.checkSignalDuration)
|
||
|
|
defer t.Stop()
|
||
|
|
|
||
|
|
//once := sync.Once{}
|
||
|
|
retryCount := 0
|
||
|
|
for {
|
||
|
|
select {
|
||
|
|
case <-ctx.Done():
|
||
|
|
return false, ctx.Err()
|
||
|
|
case <-t.C:
|
||
|
|
//1.Result
|
||
|
|
result, err := c.plcClient.ReadBool(addrResult.Addr.Add(9, 0).String())
|
||
|
|
if err != nil {
|
||
|
|
slog.Error("读取PLC信号失败",
|
||
|
|
slog.String("address", addrResult.String()),
|
||
|
|
slog.Int("retry", retryCount),
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
retryCount++
|
||
|
|
if retryCount >= c.maxRetries {
|
||
|
|
slog.Error("读取PLC完成信号失败",
|
||
|
|
slog.Any("address", addrResult),
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
return true, err
|
||
|
|
}
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
if result == valueResult {
|
||
|
|
slog.Info("收到PLC完成信号",
|
||
|
|
slog.Any("address", addrResult),
|
||
|
|
)
|
||
|
|
return true, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
//2.wait
|
||
|
|
result, err = c.plcClient.ReadBool(replayAddr.String())
|
||
|
|
if err != nil {
|
||
|
|
slog.Error("读取PLC信号失败",
|
||
|
|
slog.String("address", replayAddr.String()),
|
||
|
|
slog.Int("retry", retryCount),
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
retryCount++
|
||
|
|
if retryCount >= c.maxRetries {
|
||
|
|
slog.Error("读取PLC完成信号失败",
|
||
|
|
slog.Any("address", replayAddr),
|
||
|
|
slog.Any("error", err),
|
||
|
|
)
|
||
|
|
return false, err
|
||
|
|
}
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
if result == value {
|
||
|
|
slog.Info("收到PLC完成信号",
|
||
|
|
slog.Any("address", replayAddr),
|
||
|
|
)
|
||
|
|
return false, nil
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (c *Controller) waitReply(ctx context.Context, addr preload.MAddress, autoClear bool) error {
|
||
|
|
if err := c.WaitSignal(ctx, addr, true, true); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
if autoClear {
|
||
|
|
_ = c.plcClient.Write(addr.Address(), make([]byte, 9))
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (c *Controller) GetErrorCode() error {
|
||
|
|
addr := preload.GetMAddress("ErrorCode")
|
||
|
|
bs, err := c.plcClient.Read(addr.Address(), 8)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
v := binary.LittleEndian.Uint64(bs)
|
||
|
|
if v == 0 {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
e := plc.RobotError(v)
|
||
|
|
return &e
|
||
|
|
}
|