zhangqian
2023-10-27 d91a802e7aa2ad4075ed803b8ddc7536a91a0ef0
update
6个文件已修改
186 ■■■■■ 已修改文件
constvar/const.go 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pkg/plc/apacheplc4x/modbus.go 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pkg/plc/apacheplc4x/modbusrtu.go 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pkg/plc/modbusx/connection_manager.go 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pkg/plc/modbusx/modbus.go 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pkg/plc/modbusx/modbusrtu.go 63 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
constvar/const.go
@@ -79,3 +79,15 @@
    ParityOdd  Parity = 2 //偶校验
    ParityNull Parity = 3 //无校验
)
func (p Parity) String() string {
    switch p {
    case ParityEven:
        return "E"
    case ParityOdd:
        return "O"
    case ParityNull:
        return "N"
    }
    return ""
}
pkg/plc/apacheplc4x/modbus.go
@@ -15,31 +15,35 @@
    "time"
)
var driverManager plc4go.PlcDriverManager
func init() {
    // 创建驱动管理器
    driverManager = plc4go.NewPlcDriverManager()
    // 注册TCP传输
    transports.RegisterTcpTransport(driverManager)
    // 注册串口传输
    transports.RegisterSerialTransport(driverManager)
    // 注册驱动
    drivers.RegisterModbusTcpDriver(driverManager)
    drivers.RegisterModbusRtuDriver(driverManager)
}
func GetModbusConnection(ipAddr string) (plc4go.PlcConnection, error) {
    // 创建一个上下文,并设置 3 秒超时
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()
    conn, err := newModbusConnection(ctx, ipAddr)
    conn, err := newModbusTCPConnection(ctx, ipAddr)
    if err != nil {
        logx.Errorf("new modbus connection err: %v", err.Error())
        return nil, err
    }
    return conn, nil
}
func newModbusConnection(ctx context.Context, ipAddr string) (plc4go.PlcConnection, error) {
    // 创建驱动管理器
    driverManager := plc4go.NewPlcDriverManager()
    // 注册TCP传输
    transports.RegisterTcpTransport(driverManager)
    // 注册驱动
    //drivers.RegisterKnxDriver(driverManager)
    drivers.RegisterModbusTcpDriver(driverManager)
func newModbusTCPConnection(ctx context.Context, ipAddr string) (plc4go.PlcConnection, error) {
    // 通过TCP连接PLC设备
    connectionString := fmt.Sprintf("modbus-tcp://%s", ipAddr)
    connectionRequestChanel := driverManager.GetConnection(connectionString)
    // 等待连接响应,同时考虑上下文的超时
    select {
    case connectionResult := <-connectionRequestChanel:
pkg/plc/apacheplc4x/modbusrtu.go
@@ -15,7 +15,6 @@
func newModbusRTUConnection(c *common.RTUConfig) (plc4go.PlcConnection, error) {
    ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
    // 创建一个新的 PLC 连接
    driverManager := plc4go.NewPlcDriverManager()
    connectionString := fmt.Sprintf("modbus-rtu:serial://%s?baudrate=%d&databits=%d&stopbits=%d&parity=%s", c.SerialName, c.BaudRate, c.DataBit, c.StopBit, c.Parity)
    connectionRequestChanel := driverManager.GetConnection(connectionString)
    // 等待连接响应,同时考虑上下文的超时
pkg/plc/modbusx/connection_manager.go
@@ -2,6 +2,8 @@
import (
    "apsClient/conf"
    "apsClient/model/common"
    "apsClient/pkg/logx"
    "github.com/goburrow/modbus"
    "sync"
    "time"
@@ -49,7 +51,7 @@
    if conn, ok := connectionManager.GetConnection(ipAddr); ok {
        return conn
    }
    conn := newGetModbusConnection(ipAddr)
    conn := newModbusConnection(ipAddr)
    connectionManager.AddConnection(ipAddr, conn)
    return conn
}
@@ -65,9 +67,49 @@
    }
}
func newGetModbusConnection(ipAddr string) modbus.Client {
func newModbusConnection(ipAddr string) modbus.Client {
    handler = modbus.NewTCPClientHandler(ipAddr)
    handler.Timeout = 10 * time.Second
    handler.SlaveId = byte(conf.Conf.PLC.SlaveId)
    return modbus.NewClient(handler)
}
var rtuHandler *modbus.RTUClientHandler
func getModbusRTUConnection(c *common.RTUConfig) modbus.Client {
    if conn, ok := connectionManager.GetConnection(c.SerialName); ok {
        return conn
    }
    conn := newModbusRTUConnection(c)
    connectionManager.AddConnection(c.SerialName, conn)
    return conn
}
func unsetModbusRTUConnection(serialName string) {
    _, ok := connectionManager.GetConnection(serialName)
    if !ok {
        return
    }
    connectionManager.RemoveConnection(serialName)
    if handler != nil {
        handler.Close()
    }
}
func newModbusRTUConnection(c *common.RTUConfig) modbus.Client {
    // Modbus RTU/ASCII
    rtuHandler = modbus.NewRTUClientHandler(c.SerialName)
    rtuHandler.BaudRate = c.BaudRate
    rtuHandler.DataBits = c.DataBit
    rtuHandler.Parity = c.Parity.String()
    rtuHandler.StopBits = c.StopBit
    rtuHandler.SlaveId = 1
    rtuHandler.Timeout = 5 * time.Second
    err := rtuHandler.Connect()
    if err != nil {
        logx.Errorf("getModbusRTUConnection  Connect err:%v, config: %+v", err, c)
        return nil
    }
    return modbus.NewClient(rtuHandler)
}
pkg/plc/modbusx/modbus.go
@@ -2,7 +2,6 @@
import (
    "encoding/binary"
    "sync/atomic"
)
func Read(ipAddr string, address uint16, quantity uint16) (data []byte, err error) {
@@ -41,39 +40,6 @@
func dealErr(err error, ipAddr string) {
    if err != nil {
        unsetModbusConnection(ipAddr)       //失败则删除缓存的连接
        FailureRemainingOpportunitiesDecr() //减少失败剩余机会
    } else {
        FailureRemainingOpportunitiesReset() //重置失败剩余机会
        unsetModbusConnection(ipAddr) //失败则删除缓存的连接
    }
}
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() {
    if failureRemainingOpportunities.Load() < defaultFailureRemainingOpportunities {
        failureRemainingOpportunities.Store(defaultFailureRemainingOpportunities)
    }
    if connectionStatus.Load() == false {
        connectionStatus.Store(true)
    }
    return
}
pkg/plc/modbusx/modbusrtu.go
@@ -1,80 +1,37 @@
package modbusx
import (
    "apsClient/constvar"
    "apsClient/model/common"
    "apsClient/pkg/logx"
    "github.com/goburrow/modbus"
    "time"
)
func ReadByRTU(c *common.RTUConfig, address uint16, quantity uint16) (data []byte, err error) {
    address--
    cli, err := getModbusRTUConnection(c)
    if err != nil {
        return nil, err
    }
    cli := getModbusRTUConnection(c)
    data, err = cli.ReadHoldingRegisters(address, quantity)
    dealRTUErr(err, c.SerialName)
    if err != nil {
        cli, err = getModbusRTUConnection(c)
        if err != nil {
            return nil, err
        }
        cli = getModbusRTUConnection(c)
        data, err = cli.ReadHoldingRegisters(address, quantity)
    }
    if err != nil {
        logx.Errorf("ReadByRTU ReadHoldingRegisters err:%v", err)
        dealRTUErr(err, c.SerialName)
    }
    return
}
func WriteByRTU(c *common.RTUConfig, address uint16, value int) (err error) {
    address--
    var bytesVal []byte
    bytesVal = intToBytes(value)
    cli, err := getModbusRTUConnection(c)
    if err != nil {
        return err
    }
    cli := getModbusRTUConnection(c)
    _, err = cli.WriteMultipleRegisters(address, uint16(len(bytesVal)), bytesVal)
    dealRTUErr(err, c.SerialName)
    if err != nil {
        cli, err = getModbusRTUConnection(c)
        if err != nil {
            return err
        }
        cli = getModbusRTUConnection(c)
        _, err = cli.WriteMultipleRegisters(address, uint16(len(bytesVal)), bytesVal)
    }
    if err != nil {
        logx.Errorf("WriteByRTU WriteMultipleRegisters err:%v", err)
        dealRTUErr(err, c.SerialName)
    }
    return err
}
func getModbusRTUConnection(c *common.RTUConfig) (cli modbus.Client, err error) {
    // Modbus RTU/ASCII
    h := modbus.NewRTUClientHandler(c.SerialName)
    h.BaudRate = c.BaudRate
    h.DataBits = c.DataBit
    switch c.Parity {
    case constvar.ParityEven:
        h.Parity = "E"
    case constvar.ParityOdd:
        h.Parity = "O"
    case constvar.ParityNull:
        h.Parity = "N"
    }
    h.StopBits = c.StopBit
    h.SlaveId = 1
    h.Timeout = 5 * time.Second
    err = h.Connect()
func dealRTUErr(err error, serialName string) {
    if err != nil {
        logx.Errorf("getModbusRTUConnection  Connect err:%v, config: %+v", err, c)
        return nil, err
        unsetModbusRTUConnection(serialName) //失败则删除缓存的连接
    }
    defer h.Close()
    cli = modbus.NewClient(h)
    return
}