/* * 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 }