| | |
| | | package apacheplc4x |
| | | |
| | | import ( |
| | | "apsClient/conf" |
| | | "apsClient/pkg/logx" |
| | | "context" |
| | | "errors" |
| | |
| | | "github.com/apache/plc4x/plc4go/pkg/api/drivers" |
| | | apiModel "github.com/apache/plc4x/plc4go/pkg/api/model" |
| | | "github.com/apache/plc4x/plc4go/pkg/api/transports" |
| | | "github.com/spf13/cast" |
| | | "sync/atomic" |
| | | "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 := newGetModbusConnection(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 newGetModbusConnection(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: |
| | |
| | | |
| | | 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() |
| | |
| | | |
| | | 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() |
| | |
| | | // 执行 |
| | | readResult := <-readRequest.Execute() |
| | | if err := readResult.GetErr(); err != nil { |
| | | logx.Errorf("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 { |
| | | logx.Errorf("error an non-ok return code: %s", readResult.GetResponse().GetResponseCode(tag).GetName()) |
| | | logx.Errorf("plc4x response error code: %s", readResult.GetResponse().GetResponseCode(tag).GetName()) |
| | | return nil, errors.New("error code: " + readResult.GetResponse().GetResponseCode(tag).GetName()) |
| | | } |
| | | |
| | |
| | | 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(ipAddr string, address int, value any) (string, error) { |
| | | connection, err := GetModbusConnection(ipAddr) |
| | | dealErr(err, ipAddr) |
| | |
| | | } |
| | | defer connection.Close() |
| | | 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 { |
| | | logx.Errorf("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 { |
| | | logx.Errorf("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 { |
| | | logx.Errorf("error an non-ok return code: %s", writeResult.GetResponse().GetResponseCode(tag).GetName()) |
| | | logx.Errorf("plc4x response error code: %s", writeResult.GetResponse().GetResponseCode(tag).GetName()) |
| | | return "", errors.New("error code: " + writeResult.GetResponse().GetResponseCode(tag).GetName()) |
| | | } |
| | | |