Files
bj_power/bj_power_mes/internal/robot/common.go
T

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
}