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)
+}