From 8324f872ef3a4d0c978a9b1d062800c6a1701c12 Mon Sep 17 00:00:00 2001
From: zhangqian <zhangqian@123.com>
Date: 星期五, 01 十二月 2023 09:58:17 +0800
Subject: [PATCH] fix

---
 pkg/plc/plc4x.go |  147 ++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 114 insertions(+), 33 deletions(-)

diff --git a/pkg/plc/plc4x.go b/pkg/plc/plc4x.go
index d38ac67..a7f9d25 100644
--- a/pkg/plc/plc4x.go
+++ b/pkg/plc/plc4x.go
@@ -1,11 +1,15 @@
 package plc
 
 import (
+	"apsClient/conf"
+	"apsClient/pkg/logx"
 	"context"
 	"errors"
 	"fmt"
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
+	"github.com/spf13/cast"
 	"sync"
+	"sync/atomic"
 	"time"
 
 	plc4go "github.com/apache/plc4x/plc4go/pkg/api"
@@ -18,7 +22,7 @@
 	mu          sync.Mutex
 }
 
-func NewPlcConnectionManager() *ConnectionManager {
+func newPlcConnectionManager() *ConnectionManager {
 	return &ConnectionManager{
 		connections: make(map[string]plc4go.PlcConnection),
 	}
@@ -29,10 +33,17 @@
 	defer cm.mu.Unlock()
 
 	conn, ok := cm.connections[address]
-	return conn, ok
+	if !ok {
+		return nil, false
+	}
+	//if ok, _ := cm.CheckConnect(conn, time.Second); !ok {
+	//	conn.Close()
+	//}
+
+	return conn, true
 }
 
-var connectionManager = NewPlcConnectionManager()
+var connectionManager = newPlcConnectionManager()
 
 func (cm *ConnectionManager) AddConnection(address string, connection plc4go.PlcConnection) {
 	cm.mu.Lock()
@@ -40,24 +51,39 @@
 
 	cm.connections[address] = connection
 }
+
+func (cm *ConnectionManager) CheckConnect(conn plc4go.PlcConnection, timeout time.Duration) (bool, error) {
+	pingCh := conn.Ping()
+	timer := time.NewTimer(timeout)
+
+	select {
+	case err := <-pingCh:
+		if err == nil {
+			return true, nil
+		}
+		return false, err.GetErr()
+	case <-timer.C:
+		return false, fmt.Errorf("connection timed out after %s", timeout)
+	}
+}
+
 func GetModbusConnection(ipAddr string) (plc4go.PlcConnection, error) {
 	if conn, ok := connectionManager.GetConnection(ipAddr); ok {
-		if conn.IsConnected() {
-			return conn, nil
-		}
+		return conn, nil
 	}
-	// 鍒涘缓涓�涓笂涓嬫枃锛屽苟璁剧疆 5 绉掕秴鏃�
-	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+	// 鍒涘缓涓�涓笂涓嬫枃锛屽苟璁剧疆 3 绉掕秴鏃�
+	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 	defer cancel()
-	conn, err := NewGetModbusConnection(ctx, ipAddr)
+	conn, err := newGetModbusConnection(ctx, ipAddr)
 	if err != nil {
+		logx.Errorf("new modbus connection err: %v", err.Error())
 		return nil, err
 	}
 	connectionManager.AddConnection(ipAddr, conn)
 	return conn, nil
 }
 
-func NewGetModbusConnection(ctx context.Context, ipAddr string) (plc4go.PlcConnection, error) {
+func newGetModbusConnection(ctx context.Context, ipAddr string) (plc4go.PlcConnection, error) {
 	// 鍒涘缓椹卞姩绠$悊鍣�
 	driverManager := plc4go.NewPlcDriverManager()
 	// 娉ㄥ唽TCP浼犺緭
@@ -82,61 +108,61 @@
 	}
 }
 
-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)
+	tagAddress := getTagAddress(address, 1)
 
 	// 璇绘ā寮�
 	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)
+	tagAddress := getTagAddress(address, length)
 
 	// 璇绘ā寮�
 	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("plc4x execute 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("plc4x response error 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
 
@@ -149,37 +175,92 @@
 
 func ReadHoldingRegister(connection plc4go.PlcConnection, address, length int) ([]byte, error) {
 	if length > 1 {
-		return ReadHoldingRegisterList(connection, address, length)
+		return readHoldingRegisterList(connection, address, length)
 	}
 
-	return ReadHoldingRegisterSingle(connection, address)
+	return readHoldingRegisterSingle(connection, address)
+}
+
+func getTagAddress(address int, length int) string {
+	intType := conf.Conf.PLC.ModbusIntType
+	if intType == "" {
+		intType = "DINT"
+	}
+	if length == 1 {
+		return fmt.Sprintf("holding-register:%d:%v", address, intType)
+	} else {
+		return fmt.Sprintf("holding-register:%d:%v[%d]", address, intType, length)
+	}
 }
 
 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)
+	var tagAddress string
+	if cast.ToInt32(value) > 2<<16 {
+		tagAddress = getTagAddress(address, 2)
+	} else {
+		tagAddress = getTagAddress(address, 1)
+	}
 
 	// 鍐欐ā寮�
 	writeRequest, err := connection.WriteRequestBuilder().AddTagAddress(tag, tagAddress, value).Build()
 	if err != nil {
-		fmt.Printf("preparing read-request:%s\n", err.Error())
+		logx.Errorf("plc4x 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("plc4x execute write-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("plc4x  response error code: %s", writeResult.GetResponse().GetResponseCode(tag).GetName())
+		return "", errors.New("error  code: " + writeResult.GetResponse().GetResponseCode(tag).GetName())
 	}
 
 	result := writeResult.GetResponse().String()
 
 	return result, nil
 }
+
+func dealErr(err error, ipAddr string) {
+	if err != nil {
+		FailureRemainingOpportunitiesDecr() //鍑忓皯澶辫触鍓╀綑鏈轰細
+	} else {
+		FailureRemainingOpportunitiesReset() //閲嶇疆澶辫触鍓╀綑鏈轰細
+	}
+}
+
+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
+}

--
Gitblit v1.8.0