You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2021/04/12 12:11:24 UTC
[plc4x] branch develop updated: plc4go: introduced configuration
structs
This is an automated email from the ASF dual-hosted git repository.
sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/develop by this push:
new c4e282f plc4go: introduced configuration structs
c4e282f is described below
commit c4e282fc279fac19f05f9f6fa8a76b1b30847da4
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Mon Apr 12 14:11:10 2021 +0200
plc4go: introduced configuration structs
+ ads migrate old code to a configuration
+ s7 add a configuration
---
plc4go/internal/plc4go/ads/Configuration.go | 147 ++++++++++++++++++++++++++++
plc4go/internal/plc4go/ads/Connection.go | 134 ++++---------------------
plc4go/internal/plc4go/ads/Driver.go | 10 +-
plc4go/internal/plc4go/s7/Configuration.go | 135 +++++++++++++++++++++++++
plc4go/internal/plc4go/s7/Connection.go | 8 +-
plc4go/internal/plc4go/s7/ControllerType.go | 32 ++++++
plc4go/internal/plc4go/s7/Driver.go | 14 ++-
plc4go/internal/plc4go/s7/DriverContext.go | 90 +++++++++++++++++
plc4go/internal/plc4go/s7/TsapIdEncoder.go | 41 ++++++++
9 files changed, 493 insertions(+), 118 deletions(-)
diff --git a/plc4go/internal/plc4go/ads/Configuration.go b/plc4go/internal/plc4go/ads/Configuration.go
new file mode 100644
index 0000000..e2b379e
--- /dev/null
+++ b/plc4go/internal/plc4go/ads/Configuration.go
@@ -0,0 +1,147 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package ads
+
+import (
+ readWriteModel "github.com/apache/plc4x/plc4go/internal/plc4go/ads/readwrite/model"
+ "github.com/pkg/errors"
+ "github.com/rs/zerolog/log"
+ "strconv"
+ "strings"
+)
+
+type Configuration struct {
+ sourceAmsNetId readWriteModel.AmsNetId
+ sourceAmsPort uint16
+ targetAmsNetId readWriteModel.AmsNetId
+ targetAmsPort uint16
+}
+
+func ParseFromOptions(options map[string][]string) (Configuration, error) {
+ configuration := Configuration{}
+
+ sourceAmsNetId := getFromOptions(options, "sourceAmsNetId")
+ if sourceAmsNetId == "" {
+ return Configuration{}, errors.New("Required parameter sourceAmsNetId missing")
+ }
+ split := strings.Split(sourceAmsNetId, ".")
+ octet1, err := strconv.Atoi(split[0])
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "error parsing sourceAmsNetId")
+ }
+ octet2, err := strconv.Atoi(split[1])
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "error parsing sourceAmsNetId")
+ }
+ octet3, err := strconv.Atoi(split[2])
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "error parsing sourceAmsNetId")
+ }
+ octet4, err := strconv.Atoi(split[3])
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "error parsing sourceAmsNetId")
+ }
+ octet5, err := strconv.Atoi(split[4])
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "error parsing sourceAmsNetId")
+ }
+ octet6, err := strconv.Atoi(split[5])
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "error parsing sourceAmsNetId")
+ }
+ configuration.sourceAmsNetId = readWriteModel.AmsNetId{
+ Octet1: uint8(octet1),
+ Octet2: uint8(octet2),
+ Octet3: uint8(octet3),
+ Octet4: uint8(octet4),
+ Octet5: uint8(octet5),
+ Octet6: uint8(octet6),
+ }
+ sourceAmsPort := getFromOptions(options, "sourceAmsPort")
+ if sourceAmsPort == "" {
+ return Configuration{}, errors.New("Required parameter sourceAmsPort missing")
+ }
+ atoi, err := strconv.Atoi(sourceAmsPort)
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "error parsing sourceAmsPort")
+ }
+ configuration.sourceAmsPort = uint16(atoi)
+ targetAmsNetId := getFromOptions(options, "targetAmsNetId")
+ if sourceAmsNetId == "" {
+ return Configuration{}, errors.New("Required parameter targetAmsNetId missing")
+ }
+ split = strings.Split(targetAmsNetId, ".")
+ octet1, err = strconv.Atoi(split[0])
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "error parsing targetAmsNetId")
+ }
+ octet2, err = strconv.Atoi(split[1])
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "error parsing targetAmsNetId")
+ }
+ octet3, err = strconv.Atoi(split[2])
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "error parsing targetAmsNetId")
+ }
+ octet4, err = strconv.Atoi(split[3])
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "error parsing targetAmsNetId")
+ }
+ octet5, err = strconv.Atoi(split[4])
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "error parsing targetAmsNetId")
+ }
+ octet6, err = strconv.Atoi(split[5])
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "error parsing targetAmsNetId")
+ }
+ configuration.targetAmsNetId = readWriteModel.AmsNetId{
+ Octet1: uint8(octet1),
+ Octet2: uint8(octet2),
+ Octet3: uint8(octet3),
+ Octet4: uint8(octet4),
+ Octet5: uint8(octet5),
+ Octet6: uint8(octet6),
+ }
+ targetAmsPort := getFromOptions(options, "targetAmsPort")
+ if targetAmsPort == "" {
+ return Configuration{}, errors.New("Required parameter targetAmsPort missing")
+ }
+ atoi, err = strconv.Atoi(targetAmsPort)
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "error parsing targetAmsPort")
+ }
+ configuration.targetAmsPort = uint16(atoi)
+
+ return configuration, nil
+}
+
+func getFromOptions(options map[string][]string, key string) string {
+ if optionValues, ok := options[key]; ok {
+ if len(optionValues) <= 0 {
+ return ""
+ }
+ if len(optionValues) > 1 {
+ log.Warn().Msgf("Options %s must be unique", key)
+ }
+ return optionValues[0]
+ }
+ return ""
+}
diff --git a/plc4go/internal/plc4go/ads/Connection.go b/plc4go/internal/plc4go/ads/Connection.go
index cbacaf5..07ee7f9 100644
--- a/plc4go/internal/plc4go/ads/Connection.go
+++ b/plc4go/internal/plc4go/ads/Connection.go
@@ -20,17 +20,13 @@ package ads
import (
"fmt"
- readWriteModel "github.com/apache/plc4x/plc4go/internal/plc4go/ads/readwrite/model"
"github.com/apache/plc4x/plc4go/internal/plc4go/spi"
"github.com/apache/plc4x/plc4go/internal/plc4go/spi/interceptors"
internalModel "github.com/apache/plc4x/plc4go/internal/plc4go/spi/model"
"github.com/apache/plc4x/plc4go/internal/plc4go/spi/transports"
"github.com/apache/plc4x/plc4go/pkg/plc4go"
apiModel "github.com/apache/plc4x/plc4go/pkg/plc4go/model"
- "github.com/pkg/errors"
"github.com/rs/zerolog/log"
- "strconv"
- "strings"
"time"
)
@@ -60,128 +56,40 @@ func (m *ConnectionMetadata) CanBrowse() bool {
// TODO: maybe we can use a DefaultConnection struct here with delegates
type Connection struct {
messageCodec spi.MessageCodec
- options map[string][]string
fieldHandler spi.PlcFieldHandler
valueHandler spi.PlcValueHandler
requestInterceptor internalModel.RequestInterceptor
- // TODO: check if this is the right place here (it is kinda connection bound)
- sourceAmsNetId readWriteModel.AmsNetId
- sourceAmsPort uint16
- targetAmsNetId readWriteModel.AmsNetId
- targetAmsPort uint16
- reader *Reader
- writer *Writer
-}
-
-func NewConnection(messageCodec spi.MessageCodec, options map[string][]string, fieldHandler spi.PlcFieldHandler) (*Connection, error) {
- if err := checkForRequiredParameters(options, []string{"sourceAmsNetId", "sourceAmsPort", "targetAmsNetId", "targetAmsPort"}); err != nil {
- return nil, err
- }
- // TODO: check array
- split := strings.Split(options["sourceAmsNetId"][0], ".")
- octet1, err := strconv.Atoi(split[0])
- if err != nil {
- return nil, errors.Wrap(err, "error parsing sourceAmsNetId")
- }
- octet2, err := strconv.Atoi(split[1])
- if err != nil {
- return nil, errors.Wrap(err, "error parsing sourceAmsNetId")
- }
- octet3, err := strconv.Atoi(split[2])
- if err != nil {
- return nil, errors.Wrap(err, "error parsing sourceAmsNetId")
- }
- octet4, err := strconv.Atoi(split[3])
- if err != nil {
- return nil, errors.Wrap(err, "error parsing sourceAmsNetId")
- }
- octet5, err := strconv.Atoi(split[4])
- if err != nil {
- return nil, errors.Wrap(err, "error parsing sourceAmsNetId")
- }
- octet6, err := strconv.Atoi(split[5])
- if err != nil {
- return nil, errors.Wrap(err, "error parsing sourceAmsNetId")
- }
- sourceAmsNetId := readWriteModel.AmsNetId{
- Octet1: uint8(octet1),
- Octet2: uint8(octet2),
- Octet3: uint8(octet3),
- Octet4: uint8(octet4),
- Octet5: uint8(octet5),
- Octet6: uint8(octet6),
- }
- // TODO: check array
- sourceAmsPort, err := strconv.Atoi(options["sourceAmsPort"][0])
- if err != nil {
- return nil, errors.Wrap(err, "error parsing sourceAmsPort")
- }
- // TODO: check array
- split = strings.Split(options["targetAmsNetId"][0], ".")
- octet1, err = strconv.Atoi(split[0])
- if err != nil {
- return nil, errors.Wrap(err, "error parsing targetAmsNetId")
- }
- octet2, err = strconv.Atoi(split[1])
- if err != nil {
- return nil, errors.Wrap(err, "error parsing targetAmsNetId")
- }
- octet3, err = strconv.Atoi(split[2])
- if err != nil {
- return nil, errors.Wrap(err, "error parsing targetAmsNetId")
- }
- octet4, err = strconv.Atoi(split[3])
- if err != nil {
- return nil, errors.Wrap(err, "error parsing targetAmsNetId")
- }
- octet5, err = strconv.Atoi(split[4])
- if err != nil {
- return nil, errors.Wrap(err, "error parsing targetAmsNetId")
- }
- octet6, err = strconv.Atoi(split[5])
- if err != nil {
- return nil, errors.Wrap(err, "error parsing targetAmsNetId")
- }
- targetAmsNetId := readWriteModel.AmsNetId{
- Octet1: uint8(octet1),
- Octet2: uint8(octet2),
- Octet3: uint8(octet3),
- Octet4: uint8(octet4),
- Octet5: uint8(octet5),
- Octet6: uint8(octet6),
- }
- // TODO: check array
- targetAmsPort, err := strconv.Atoi(options["targetAmsPort"][0])
- if err != nil {
- return nil, errors.Wrap(err, "error prasing targetAmsPort")
- }
- reader := *NewReader(messageCodec, targetAmsNetId, uint16(targetAmsPort), sourceAmsNetId, uint16(sourceAmsPort))
- writer := *NewWriter(messageCodec, targetAmsNetId, uint16(targetAmsPort), sourceAmsNetId, uint16(sourceAmsPort), &reader)
+ configuration Configuration
+ reader *Reader
+ writer *Writer
+}
+
+func NewConnection(messageCodec spi.MessageCodec, configuration Configuration, fieldHandler spi.PlcFieldHandler) (*Connection, error) {
+ reader := *NewReader(
+ messageCodec,
+ configuration.targetAmsNetId,
+ configuration.targetAmsPort,
+ configuration.sourceAmsNetId,
+ configuration.sourceAmsPort,
+ )
+ writer := *NewWriter(
+ messageCodec,
+ configuration.targetAmsNetId,
+ configuration.targetAmsPort,
+ configuration.sourceAmsNetId,
+ configuration.sourceAmsPort,
+ &reader,
+ )
return &Connection{
messageCodec: messageCodec,
- options: options,
fieldHandler: fieldHandler,
valueHandler: NewValueHandler(),
requestInterceptor: interceptors.NewSingleItemRequestInterceptor(),
- targetAmsNetId: targetAmsNetId,
- targetAmsPort: uint16(targetAmsPort),
- sourceAmsNetId: sourceAmsNetId,
- sourceAmsPort: uint16(sourceAmsPort),
reader: &reader,
writer: &writer,
}, nil
}
-// TODO: move to a common utils place
-func checkForRequiredParameters(options map[string][]string, requiredParameters []string) error {
- for _, parameter := range requiredParameters {
- if options[parameter] == nil {
- return errors.Errorf("required parameter %s missing", parameter)
- }
- }
- return nil
-}
-
func (m *Connection) Connect() <-chan plc4go.PlcConnectionConnectResult {
log.Trace().Msg("Connecting")
ch := make(chan plc4go.PlcConnectionConnectResult)
diff --git a/plc4go/internal/plc4go/ads/Driver.go b/plc4go/internal/plc4go/ads/Driver.go
index a6cff37..f628f61 100644
--- a/plc4go/internal/plc4go/ads/Driver.go
+++ b/plc4go/internal/plc4go/ads/Driver.go
@@ -81,8 +81,16 @@ func (m *Driver) GetConnection(transportUrl url.URL, transports map[string]trans
codec := NewMessageCodec(transportInstance)
log.Debug().Msgf("working with codec %#v", codec)
+ configuration, err := ParseFromOptions(options)
+ if err != nil {
+ log.Error().Err(err).Msgf("Invalid options")
+ ch := make(chan plc4go.PlcConnectionConnectResult)
+ ch <- plc4go.NewPlcConnectionConnectResult(nil, errors.Wrap(err, "invalid configuration"))
+ return ch
+ }
+
// Create the new connection
- connection, err := NewConnection(codec, options, m.fieldHandler)
+ connection, err := NewConnection(codec, configuration, m.fieldHandler)
if err != nil {
ch := make(chan plc4go.PlcConnectionConnectResult)
go func() {
diff --git a/plc4go/internal/plc4go/s7/Configuration.go b/plc4go/internal/plc4go/s7/Configuration.go
new file mode 100644
index 0000000..127e36e
--- /dev/null
+++ b/plc4go/internal/plc4go/s7/Configuration.go
@@ -0,0 +1,135 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package s7
+
+import (
+ "github.com/pkg/errors"
+ "github.com/rs/zerolog/log"
+ "strconv"
+)
+
+type Configuration struct {
+ localRack int32
+ localSlot int32
+ remoteRack int32
+ remoteSlot int32
+ pduSize uint16
+ maxAmqCaller uint16
+ maxAmqCallee uint16
+ controllerType ControllerType
+}
+
+func ParseFromOptions(options map[string][]string) (Configuration, error) {
+ configuration := Configuration{
+ localRack: 1,
+ localSlot: 1,
+ remoteRack: 0,
+ remoteSlot: 0,
+ pduSize: 1024,
+ maxAmqCaller: 8,
+ maxAmqCallee: 8,
+ controllerType: ControllerType_UNKNOWN,
+ }
+ if localRackString := getFromOptions(options, "local-rack"); localRackString != "" {
+ atoi, err := strconv.Atoi(localRackString)
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "Error parsing local-rack")
+ }
+ configuration.localRack = int32(atoi)
+ }
+ if localSlotString := getFromOptions(options, "local-rack"); localSlotString != "" {
+ atoi, err := strconv.Atoi(localSlotString)
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "Error parsing local-slot")
+ }
+ configuration.localSlot = int32(atoi)
+ }
+ if remoteRackString := getFromOptions(options, "remote-rack"); remoteRackString != "" {
+ atoi, err := strconv.Atoi(remoteRackString)
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "Error parsing remote-rack")
+ }
+ configuration.remoteRack = int32(atoi)
+ }
+ if remoteSlotString := getFromOptions(options, "remote-rack"); remoteSlotString != "" {
+ atoi, err := strconv.Atoi(remoteSlotString)
+ if err != nil {
+ return Configuration{}, errors.Wrap(err, "Error parsing remote-slot")
+ }
+ configuration.remoteSlot = int32(atoi)
+ }
+ if controllerTypeString := getFromOptions(options, "controller-type"); controllerTypeString != "" {
+ switch controllerTypeString {
+ case "ANY":
+ configuration.controllerType = ControllerType_ANY
+ case "S7_300":
+ configuration.controllerType = ControllerType_S7_300
+ case "S7_400":
+ configuration.controllerType = ControllerType_S7_400
+ case "S7_1200":
+ configuration.controllerType = ControllerType_S7_1200
+ case "S7_1500":
+ configuration.controllerType = ControllerType_S7_1500
+ case "LOGO":
+ configuration.controllerType = ControllerType_LOGO
+ default:
+ return Configuration{}, errors.Errorf("Unknown controller type %s", controllerTypeString)
+ }
+ }
+
+ pduSizeString := getFromOptions(options, "pdu-size")
+ if pduSizeString != "" {
+ atoi, err := strconv.Atoi(pduSizeString)
+ if err != nil {
+ return Configuration{}, errors.Wrapf(err, "Error parsing pdu-size %s", pduSizeString)
+ }
+ configuration.pduSize = uint16(atoi)
+ }
+
+ if maxAmqCallerString := getFromOptions(options, "max-amq-caller"); maxAmqCallerString != "" {
+ atoi, err := strconv.Atoi(maxAmqCallerString)
+ if err != nil {
+ return Configuration{}, errors.Wrapf(err, "Error parsing max-amq-caller %s", maxAmqCallerString)
+ }
+ configuration.maxAmqCaller = uint16(atoi)
+ }
+
+ if maxAmqCalleeString := getFromOptions(options, "max-amq-callee"); maxAmqCalleeString != "" {
+ atoi, err := strconv.Atoi(maxAmqCalleeString)
+ if err != nil {
+ return Configuration{}, errors.Wrapf(err, "Error parsing max-amq-callee %s", maxAmqCalleeString)
+ }
+ configuration.maxAmqCallee = uint16(atoi)
+ }
+ return configuration, nil
+}
+
+func getFromOptions(options map[string][]string, key string) string {
+ if optionValues, ok := options[key]; ok {
+ if len(optionValues) <= 0 {
+ return ""
+ }
+ if len(optionValues) > 1 {
+ log.Warn().Msgf("Options %s must be unique", key)
+ }
+ return optionValues[0]
+ }
+ return ""
+}
diff --git a/plc4go/internal/plc4go/s7/Connection.go b/plc4go/internal/plc4go/s7/Connection.go
index ccf5282..620b77d 100644
--- a/plc4go/internal/plc4go/s7/Connection.go
+++ b/plc4go/internal/plc4go/s7/Connection.go
@@ -56,16 +56,18 @@ func (m ConnectionMetadata) CanBrowse() bool {
// TODO: maybe we can use a DefaultConnection struct here with delegates
type Connection struct {
messageCodec spi.MessageCodec
- options map[string][]string
+ configuration Configuration
+ driverContext DriverContext
fieldHandler spi.PlcFieldHandler
valueHandler spi.PlcValueHandler
requestInterceptor internalModel.RequestInterceptor
}
-func NewConnection(messageCodec spi.MessageCodec, options map[string][]string, fieldHandler spi.PlcFieldHandler) Connection {
+func NewConnection(messageCodec spi.MessageCodec, configuration Configuration, driverContext DriverContext, fieldHandler spi.PlcFieldHandler) Connection {
return Connection{
messageCodec: messageCodec,
- options: options,
+ configuration: configuration,
+ driverContext: driverContext,
fieldHandler: fieldHandler,
valueHandler: NewValueHandler(),
requestInterceptor: interceptors.NewSingleItemRequestInterceptor(),
diff --git a/plc4go/internal/plc4go/s7/ControllerType.go b/plc4go/internal/plc4go/s7/ControllerType.go
new file mode 100644
index 0000000..c52d671
--- /dev/null
+++ b/plc4go/internal/plc4go/s7/ControllerType.go
@@ -0,0 +1,32 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package s7
+
+type ControllerType int
+
+const (
+ ControllerType_UNKNOWN = -0x1
+ ControllerType_ANY = 0x0
+ ControllerType_S7_300 = 0x1
+ ControllerType_S7_400 = 0x2
+ ControllerType_S7_1200 = 0x3
+ ControllerType_S7_1500 = 0x4
+ ControllerType_LOGO = 0x5
+)
diff --git a/plc4go/internal/plc4go/s7/Driver.go b/plc4go/internal/plc4go/s7/Driver.go
index e49d504..9a9a596 100644
--- a/plc4go/internal/plc4go/s7/Driver.go
+++ b/plc4go/internal/plc4go/s7/Driver.go
@@ -83,8 +83,20 @@ func (m Driver) GetConnection(transportUrl url.URL, transports map[string]transp
codec := NewMessageCodec(transportInstance)
log.Debug().Msgf("working with codec %#v", codec)
+ configuration, err := ParseFromOptions(options)
+ if err != nil {
+ log.Error().Err(err).Msgf("Invalid options")
+ ch := make(chan plc4go.PlcConnectionConnectResult)
+ go func() {
+ ch <- plc4go.NewPlcConnectionConnectResult(nil, errors.Wrap(err, "Invalid options"))
+ }()
+ return ch
+ }
+
+ driverContext, err := NewDriverContext(configuration)
+
// Create the new connection
- connection := NewConnection(codec, options, m.fieldHandler)
+ connection := NewConnection(codec, configuration, driverContext, m.fieldHandler)
log.Info().Stringer("connection", connection).Msg("created connection, connecting now")
return connection.Connect()
}
diff --git a/plc4go/internal/plc4go/s7/DriverContext.go b/plc4go/internal/plc4go/s7/DriverContext.go
new file mode 100644
index 0000000..64d53f5
--- /dev/null
+++ b/plc4go/internal/plc4go/s7/DriverContext.go
@@ -0,0 +1,90 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package s7
+
+import (
+ "github.com/apache/plc4x/plc4go/internal/plc4go/s7/readwrite/model"
+)
+
+type DriverContext struct {
+ PassiveMode bool
+ CallingTsapId int32
+ CalledTsapId int32
+ CotpTpduSize model.COTPTpduSize
+ PduSize uint16
+ MaxAmqCaller uint16
+ MaxAmqCallee uint16
+ ControllerType ControllerType
+}
+
+func NewDriverContext(configuration Configuration) (DriverContext, error) {
+ callingTsapId := encodeS7TsapId(model.DeviceGroup_OTHERS, configuration.localRack, configuration.localSlot)
+ calledTsapId := encodeS7TsapId(model.DeviceGroup_PG_OR_PC, configuration.remoteRack, configuration.remoteSlot)
+
+ controllerType := configuration.controllerType
+ if controllerType == ControllerType_UNKNOWN {
+ controllerType = ControllerType_ANY
+ }
+
+ pduSize := configuration.pduSize
+ // The Siemens LOGO device seems to only work with very limited settings,
+ // so we're overriding some of the defaults.
+ if controllerType == ControllerType_LOGO && pduSize == 1024 {
+ pduSize = 480
+ }
+
+ // Initialize the parameters with initial version (Will be updated during the login process)
+ cotpTpduSize := getNearestMatchingTpduSize(pduSize)
+ // The PDU size is theoretically not bound by the COTP TPDU size, however having a larger
+ // PDU size would make the code extremely complex. But even if the protocol would allow this
+ // I have never seen this happen in reality. Making is smaller would unnecessarily limit the
+ // size, so we're setting it to the maximum that can be included.
+ pduSize = cotpTpduSize.SizeInBytes() - 16
+ maxAmqCaller := configuration.maxAmqCaller
+ maxAmqCallee := configuration.maxAmqCallee
+ return DriverContext{
+ CallingTsapId: callingTsapId,
+ CalledTsapId: calledTsapId,
+ ControllerType: controllerType,
+ PduSize: pduSize,
+ MaxAmqCaller: maxAmqCaller,
+ MaxAmqCallee: maxAmqCallee,
+ }, nil
+}
+
+func getNearestMatchingTpduSize(tpduSizeParameter uint16) model.COTPTpduSize {
+ switch {
+ case model.COTPTpduSize_SIZE_128.SizeInBytes() >= tpduSizeParameter:
+ return model.COTPTpduSize_SIZE_128
+ case model.COTPTpduSize_SIZE_256.SizeInBytes() >= tpduSizeParameter:
+ return model.COTPTpduSize_SIZE_256
+ case model.COTPTpduSize_SIZE_512.SizeInBytes() >= tpduSizeParameter:
+ return model.COTPTpduSize_SIZE_512
+ case model.COTPTpduSize_SIZE_1024.SizeInBytes() >= tpduSizeParameter:
+ return model.COTPTpduSize_SIZE_1024
+ case model.COTPTpduSize_SIZE_2048.SizeInBytes() >= tpduSizeParameter:
+ return model.COTPTpduSize_SIZE_2048
+ case model.COTPTpduSize_SIZE_4096.SizeInBytes() >= tpduSizeParameter:
+ return model.COTPTpduSize_SIZE_4096
+ case model.COTPTpduSize_SIZE_8192.SizeInBytes() >= tpduSizeParameter:
+ return model.COTPTpduSize_SIZE_8192
+ }
+ return model.COTPTpduSize(0)
+}
diff --git a/plc4go/internal/plc4go/s7/TsapIdEncoder.go b/plc4go/internal/plc4go/s7/TsapIdEncoder.go
new file mode 100644
index 0000000..2941557
--- /dev/null
+++ b/plc4go/internal/plc4go/s7/TsapIdEncoder.go
@@ -0,0 +1,41 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package s7
+
+import "github.com/apache/plc4x/plc4go/internal/plc4go/s7/readwrite/model"
+
+func encodeS7TsapId(deviceGroup model.DeviceGroup, rack int32, slot int32) int32 {
+ firstByte := int32(deviceGroup) << 8
+ secondByte := (rack << 4) | (slot & 0x0F)
+ return firstByte | secondByte
+}
+
+func decodeDeviceGroup(tsapId int32) model.DeviceGroup {
+ deviceGroupCode := int8((tsapId >> 8) & (0xFF))
+ return model.DeviceGroupByValue(deviceGroupCode)
+}
+
+func decodeRack(tsapId int32) int64 {
+ return int64((tsapId >> 4) & 0xF)
+}
+
+func decodeSlot(tsapId int32) int64 {
+ return int64(tsapId & 0xF)
+}