zhangqian
2023-09-16 fbae58e8f6e6159325ef41b85917ddb468d1b98a
读写plc连续失败20次认为失去心跳
5个文件已修改
104 ■■■■■ 已修改文件
api/v1/plc.go 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
crontask/cron_task.go 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pkg/plc/modbusx/connection_manager.go 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pkg/plc/modbusx/modbus.go 50 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/plc.go 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
api/v1/plc.go
@@ -6,10 +6,8 @@
    "apsClient/model/response"
    _ "apsClient/model/response"
    "apsClient/pkg/contextx"
    "apsClient/pkg/ecode"
    "apsClient/pkg/plc"
    "apsClient/pkg/plc/modbusx"
    "apsClient/service"
    "fmt"
    "github.com/gin-gonic/gin"
    "github.com/spf13/cast"
)
@@ -35,15 +33,9 @@
    resp.FinishNumber = cast.ToInt(finishNumber)
    resp.TotalNumber = cast.ToInt(totalNumber)
    plcConfig, code := service.NewDevicePlcService().GetDevicePlc()
    if code != ecode.OK {
        return
    }
    plcStatus := 1 //断开连接
    ipAddr := fmt.Sprintf("%s:%v", plcConfig.Address, plcConfig.Port)
    _, err := plc.GetModbusConnection(ipAddr)
    if err == nil {
    isConnect := modbusx.IsConnect()
    if isConnect {
        if resp.FinishNumber > 0 { //生产
            plcStatus = 2
        } else { //待机
crontask/cron_task.go
@@ -33,6 +33,7 @@
            if addressItem.FieldName == constvar.PlcStartAddressTypeFinishNumber {
                value, err := service.PlcReadDirect(plcConfig, addressItem.StartAddress, addressItem.Length, addressItem.Type)
                if err != nil {
                    logx.Infof("plc read finish number err: %v", err)
                    continue
                }
                finishNumber := cast.ToInt64(value)
@@ -40,7 +41,7 @@
                    service.PlcCacheSet(addressItem.Position, constvar.PlcCacheKeyFinishNumber, finishNumber)
                    _ = service.NewProgressService().UpdateProgress(addressItem.Position, cast.ToInt64(finishNumber))
                }
                logx.Infof("plc read finish number:%v, err:%v", finishNumber, err)
                logx.Infof("plc read finish number: %v", finishNumber)
            }
        }
@@ -58,6 +59,7 @@
            if addressItem.FieldName == constvar.PlcStartAddressTypeTotalNumber {
                value, err := service.PlcReadDirect(plcConfig, addressItem.StartAddress, addressItem.Length, addressItem.Type)
                if err != nil {
                    logx.Infof("plc read total number err: %v", err)
                    continue
                }
                totalNumber := cast.ToInt64(value)
@@ -65,7 +67,7 @@
                    service.PlcCacheSet(addressItem.Position, constvar.PlcCacheKeyTotalNumber, totalNumber)
                    _ = service.NewProgressService().UpdateProgress(addressItem.Position, cast.ToInt64(totalNumber))
                }
                logx.Infof("plc read total number:%v, err:%v", totalNumber, err)
                logx.Infof("plc read total number: %v", totalNumber)
            }
        }
pkg/plc/modbusx/connection_manager.go
@@ -3,7 +3,6 @@
import (
    "github.com/goburrow/modbus"
    "sync"
    "time"
)
type ConnectionManager struct {
@@ -37,10 +36,11 @@
    cm.connections[address] = connection
}
func (cm *ConnectionManager) CheckConnect(conn modbus.Client, timeout time.Duration) (bool, error) {
    return true, nil
func (cm *ConnectionManager) RemoveConnection(address string) {
    cm.mu.Lock()
    defer cm.mu.Unlock()
    delete(cm.connections, address)
}
func getModbusConnection(ipAddr string) modbus.Client {
    if conn, ok := connectionManager.GetConnection(ipAddr); ok {
        return conn
@@ -50,6 +50,14 @@
    return conn
}
func unsetModbusConnection(ipAddr string) {
    _, ok := connectionManager.GetConnection(ipAddr)
    if !ok {
        return
    }
    connectionManager.RemoveConnection(ipAddr)
}
func newGetModbusConnection(ipAddr string) modbus.Client {
    return modbus.TCPClient(ipAddr)
}
pkg/plc/modbusx/modbus.go
@@ -2,11 +2,13 @@
import (
    "encoding/json"
    "sync/atomic"
)
func Read(ipAddr string, address uint16, quantity uint16) (data []byte, err error) {
    cli := getModbusConnection(ipAddr)
    data, err = cli.ReadHoldingRegisters(address, quantity)
    dealErr(err, ipAddr)
    return
}
@@ -17,19 +19,41 @@
    }
    cli := getModbusConnection(ipAddr)
    _, err = cli.WriteMultipleRegisters(address, uint16(len(bytesVal)), bytesVal)
    dealErr(err, ipAddr)
    return err
}
func dealErr(err error, ipAddr string) {
    if err != nil {
        return err
        unsetModbusConnection(ipAddr)       //失败则删除缓存的连接
        FailureRemainingOpportunitiesDecr() //减少失败剩余机会
    } else {
        FailureRemainingOpportunitiesReset() //重置失败剩余机会
    }
    //time.Sleep(time.Second)
    //// 校验写入的数据
    //result, err := cli.ReadHoldingRegisters(address, uint16(len(bytesVal)))
    //if err != nil {
    //    return err
    //}
    //resultVal := int(binary.BigEndian.Uint16(result))
    //valueInt := cast.ToInt(value)
    //if resultVal != valueInt {
    //    return errors.New("write result not equal read result")
    //}
    return nil
}
var connectionStatus atomic.Bool
var failureRemainingOpportunities atomic.Int64
const (
    defaultFailureRemainingOpportunities = 20
)
func IsConnect() bool {
    return connectionStatus.Load()
}
func FailureRemainingOpportunitiesDecr() {
    newValue := failureRemainingOpportunities.Add(-1)
    if newValue <= 0 {
        connectionStatus.Store(false)
    }
    return
}
func FailureRemainingOpportunitiesReset() {
    failureRemainingOpportunities.Store(defaultFailureRemainingOpportunities)
    connectionStatus.Store(true)
    return
}
service/plc.go
@@ -116,12 +116,6 @@
    var (
        ipAddr string
    )
    if plcConfig.CurrentTryTimes > plcConfig.MaxTryTimes {
        logx.Errorf("plc write try time beyond max try times, err: %v", plcConfig.CurrentErr)
        return plcConfig.CurrentErr
    }
    plcConfig.CurrentTryTimes++
    if plcConfig.Method == constvar.PlcMethodModbusTCP {
        ipAddr = fmt.Sprintf("%s:%v", plcConfig.Address, plcConfig.Port)
        //conn, err := plc.GetModbusConnection(ipAddr)
@@ -135,8 +129,7 @@
        err = modbusx.Write(ipAddr, uint16(address), value)
        if err != nil {
            logx.Errorf("plc write failed, address: %v, value: %v, err: %v", address, value, err.Error())
            plcConfig.CurrentErr = err
            return PlcWriteDirect(plcConfig, address, value)
            return err
        }
        logx.Infof("plc write ok, address: %v, value: %v", address, value)
    } else if plcConfig.Method == constvar.PlcMethodSerial {
@@ -154,12 +147,6 @@
    var (
        ipAddr string
    )
    if plcConfig.CurrentTryTimes > plcConfig.MaxTryTimes {
        logx.Errorf("plc read try time beyond max try times, err: %v", plcConfig.CurrentErr)
        return nil, plcConfig.CurrentErr
    }
    plcConfig.CurrentTryTimes++
    if plcConfig.Method == constvar.PlcMethodModbusTCP {
        ipAddr = fmt.Sprintf("%s:%v", plcConfig.Address, plcConfig.Port)
        //conn, err := plc.GetModbusConnection(ipAddr)
@@ -170,8 +157,7 @@
        //value, err := plc.ReadHoldingRegister(conn, address, dataLength)
        value, err := modbusx.Read(ipAddr, uint16(address), uint16(dataLength))
        if err != nil {
            plcConfig.CurrentErr = err
            return PlcReadDirect(plcConfig, address, dataLength, valueType)
            return nil, err
        }
        switch valueType {
        case constvar.PlcStartAddressValueTypeString: