zhangqian
2023-09-12 b555874608be2e4bb40cceba60b497c04caef842
pkg/plc/plc4x.go
@@ -1,22 +1,68 @@
package plc
import (
   "apsClient/pkg/logx"
   "context"
   "errors"
   "fmt"
   apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
   "sync"
   "time"
   plc4go "github.com/apache/plc4x/plc4go/pkg/api"
   "github.com/apache/plc4x/plc4go/pkg/api/drivers"
   "github.com/apache/plc4x/plc4go/pkg/api/transports"
)
func NewModbusConnection(ipAddr string) (plc4go.PlcConnection, error) {
type ConnectionManager struct {
   connections map[string]plc4go.PlcConnection
   mu          sync.Mutex
}
func newPlcConnectionManager() *ConnectionManager {
   return &ConnectionManager{
      connections: make(map[string]plc4go.PlcConnection),
   }
}
func (cm *ConnectionManager) GetConnection(address string) (plc4go.PlcConnection, bool) {
   cm.mu.Lock()
   defer cm.mu.Unlock()
   conn, ok := cm.connections[address]
   return conn, ok
}
var connectionManager = newPlcConnectionManager()
func (cm *ConnectionManager) AddConnection(address string, connection plc4go.PlcConnection) {
   cm.mu.Lock()
   defer cm.mu.Unlock()
   cm.connections[address] = connection
}
func GetModbusConnection(ipAddr string) (plc4go.PlcConnection, error) {
   if conn, ok := connectionManager.GetConnection(ipAddr); ok {
      if conn.IsConnected() {
         return conn, nil
      }
   }
   // 创建一个上下文,并设置 3 秒超时
   ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
   defer cancel()
   conn, err := newGetModbusConnection(ctx, ipAddr)
   if err != nil {
      return nil, err
   }
   connectionManager.AddConnection(ipAddr, conn)
   return conn, nil
}
func newGetModbusConnection(ctx context.Context, ipAddr string) (plc4go.PlcConnection, error) {
   // 创建驱动管理器
   driverManager := plc4go.NewPlcDriverManager()
   // 注册TCP传输
   transports.RegisterTcpTransport(driverManager)
   // 注册驱动
   //drivers.RegisterKnxDriver(driverManager)
   drivers.RegisterModbusTcpDriver(driverManager)
@@ -25,69 +71,73 @@
   connectionString := fmt.Sprintf("modbus-tcp://%s", ipAddr)
   connectionRequestChanel := driverManager.GetConnection(connectionString)
   // 等待连接响应
   connectionResult := <-connectionRequestChanel
   // 判断是否连接成功
   if err := connectionResult.GetErr(); err != nil {
      return nil, err
   // 等待连接响应,同时考虑上下文的超时
   select {
   case connectionResult := <-connectionRequestChanel:
      if err := connectionResult.GetErr(); err != nil {
         return nil, err
      }
      return connectionResult.GetConnection(), nil
   case <-ctx.Done():
      return nil, ctx.Err()
   }
   return connectionResult.GetConnection(), nil
}
func ReadHoldingRegisterSingle(connection plc4go.PlcConnection, address int) ([]byte, error) {
func readHoldingRegisterSingle(connection plc4go.PlcConnection, address int) ([]byte, error) {
   tag := fmt.Sprintf("tag:%v", address)
   tagAddress := fmt.Sprintf("holding-register:%d:UINT", address)
   // 读模式
   readRequest, err := connection.ReadRequestBuilder().AddTagAddress("tag", tagAddress).Build()
   readRequest, err := connection.ReadRequestBuilder().AddTagAddress(tag, tagAddress).Build()
   if err != nil {
      fmt.Printf("preparing read-request:%s\n", err.Error())
      logx.Errorf("preparing read-request:%s\n", err.Error())
      return nil, err
   }
   // 执行
   readResult := <-readRequest.Execute()
   if err := readResult.GetErr(); err != nil {
      fmt.Printf("execting read-request:%s\n", err.Error())
      logx.Errorf("execting read-request:%s\n", err.Error())
      return nil, err
   }
   // 判断响应码是否正确
   if readResult.GetResponse().GetResponseCode("tag") != apiModel.PlcResponseCode_OK {
      fmt.Printf("error an non-ok return code: %s", readResult.GetResponse().GetResponseCode("tag").GetName())
   if readResult.GetResponse().GetResponseCode(tag) != apiModel.PlcResponseCode_OK {
      logx.Errorf("error an non-ok return code: %s", readResult.GetResponse().GetResponseCode(tag).GetName())
      return nil, nil
   }
   value := readResult.GetResponse().GetValue("tag")
   value := readResult.GetResponse().GetValue(tag)
   return value.GetRaw(), err
}
func ReadHoldingRegisterList(connection plc4go.PlcConnection, address, length int) ([]byte, error) {
func readHoldingRegisterList(connection plc4go.PlcConnection, address, length int) ([]byte, error) {
   tag := fmt.Sprintf("tag:%v:%v", address, length)
   tagAddress := fmt.Sprintf("holding-register:%d:UINT[%d]", address, length)
   // 读模式
   readRequest, err := connection.ReadRequestBuilder().AddTagAddress("tag", tagAddress).Build()
   readRequest, err := connection.ReadRequestBuilder().AddTagAddress(tag, tagAddress).Build()
   if err != nil {
      fmt.Printf("preparing read-request:%s\n", err.Error())
      logx.Errorf("preparing read-request:%s\n", err.Error())
      return nil, err
   }
   // 执行
   readResult := <-readRequest.Execute()
   if err := readResult.GetErr(); err != nil {
      fmt.Printf("execting read-request:%s\n", err.Error())
      logx.Errorf("execting read-request:%s\n", err.Error())
      return nil, err
   }
   // 判断响应码是否正确
   if readResult.GetResponse().GetResponseCode("tag") != apiModel.PlcResponseCode_OK {
      fmt.Printf("error an non-ok return code: %s", readResult.GetResponse().GetResponseCode("tag").GetName())
      return nil, errors.New("error  code: " + readResult.GetResponse().GetResponseCode("tag").GetName())
   if readResult.GetResponse().GetResponseCode(tag) != apiModel.PlcResponseCode_OK {
      logx.Errorf("error an non-ok return code: %s", readResult.GetResponse().GetResponseCode(tag).GetName())
      return nil, errors.New("error  code: " + readResult.GetResponse().GetResponseCode(tag).GetName())
   }
   value := readResult.GetResponse().GetValue("tag")
   value := readResult.GetResponse().GetValue(tag)
   var result []byte
@@ -98,27 +148,36 @@
   return result, nil
}
func ReadHoldingRegister(connection plc4go.PlcConnection, address, length int) ([]byte, error) {
   if length > 1 {
      return readHoldingRegisterList(connection, address, length)
   }
   return readHoldingRegisterSingle(connection, address)
}
func WriteHoldingRegister(connection plc4go.PlcConnection, address int, value any) (string, error) {
   tag := fmt.Sprintf("tag:%v:w", address)
   tagAddress := fmt.Sprintf("holding-register:%d:UINT", address)
   // 写模式
   writeRequest, err := connection.WriteRequestBuilder().AddTagAddress("tag", tagAddress, value).Build()
   writeRequest, err := connection.WriteRequestBuilder().AddTagAddress(tag, tagAddress, value).Build()
   if err != nil {
      fmt.Printf("preparing read-request:%s\n", err.Error())
      logx.Errorf("preparing read-request:%s\n", err.Error())
      return "", err
   }
   // 执行
   writeResult := <-writeRequest.Execute()
   if err := writeResult.GetErr(); err != nil {
      fmt.Printf("execting read-request:%s\n", err.Error())
      logx.Errorf("execting read-request:%s\n", err.Error())
      return "", err
   }
   // 判断响应码是否正确
   if writeResult.GetResponse().GetResponseCode("tag") != apiModel.PlcResponseCode_OK {
      fmt.Printf("error an non-ok return code: %s", writeResult.GetResponse().GetResponseCode("tag").GetName())
      return "", errors.New("error  code: " + writeResult.GetResponse().GetResponseCode("tag").GetName())
   if writeResult.GetResponse().GetResponseCode(tag) != apiModel.PlcResponseCode_OK {
      logx.Errorf("error an non-ok return code: %s", writeResult.GetResponse().GetResponseCode(tag).GetName())
      return "", errors.New("error  code: " + writeResult.GetResponse().GetResponseCode(tag).GetName())
   }
   result := writeResult.GetResponse().String()