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 2022/07/26 09:50:35 UTC

[plc4x] branch develop updated: feat(plc4go/cbus): initial c-bus driver implementation

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 6021471df feat(plc4go/cbus): initial c-bus driver implementation
6021471df is described below

commit 6021471df7036f2f285aa006404ae681fe231dd0
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Tue Jul 26 11:50:28 2022 +0200

    feat(plc4go/cbus): initial c-bus driver implementation
---
 plc4go/internal/cbus/Configuration.go              |  58 ++++++++
 plc4go/internal/cbus/Connection.go                 | 164 +++++++++++++++++++++
 plc4go/internal/cbus/Driver.go                     | 110 ++++++++++++++
 plc4go/internal/cbus/DriverContext.go              |  29 ++++
 plc4go/internal/cbus/Field.go                      |  69 +++++++++
 plc4go/internal/cbus/FieldHandler.go               |  47 ++++++
 plc4go/internal/cbus/MessageCodec.go               | 155 +++++++++++++++++++
 plc4go/internal/cbus/Reader.go                     |  55 +++++++
 plc4go/internal/cbus/ValueHandler.go               |  32 ++++
 plc4go/internal/cbus/Writer.go                     |  53 +++++++
 plc4go/internal/cbus/fieldtype_string.go           |  40 +++++
 plc4go/pkg/api/drivers/drivers.go                  |   6 +
 plc4go/pom.xml                                     |  19 ++-
 .../apache/plc4x/java/cbus/RandomPackagesTest.java |   1 -
 14 files changed, 836 insertions(+), 2 deletions(-)

diff --git a/plc4go/internal/cbus/Configuration.go b/plc4go/internal/cbus/Configuration.go
new file mode 100644
index 000000000..09f71165e
--- /dev/null
+++ b/plc4go/internal/cbus/Configuration.go
@@ -0,0 +1,58 @@
+/*
+ * 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
+ *
+ *   https://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 cbus
+
+import (
+	"strconv"
+
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+)
+
+type Configuration struct {
+	srchk bool
+}
+
+func ParseFromOptions(options map[string][]string) (Configuration, error) {
+	configuration := Configuration{
+		srchk: true,
+	}
+	if srchk := getFromOptions(options, "srchk"); srchk != "" {
+		parseBool, err := strconv.ParseBool(srchk)
+		if err != nil {
+			return Configuration{}, errors.Wrap(err, "Error parsing srchk")
+		}
+		configuration.srchk = parseBool
+	}
+	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/cbus/Connection.go b/plc4go/internal/cbus/Connection.go
new file mode 100644
index 000000000..6370704d4
--- /dev/null
+++ b/plc4go/internal/cbus/Connection.go
@@ -0,0 +1,164 @@
+/*
+ * 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
+ *
+ *   https://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 cbus
+
+import (
+	"fmt"
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	"github.com/apache/plc4x/plc4go/internal/spi/default"
+	internalModel "github.com/apache/plc4x/plc4go/internal/spi/model"
+	"github.com/apache/plc4x/plc4go/pkg/api"
+	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+	"sync"
+)
+
+type AlphaGenerator struct {
+	currentAlpha byte
+	lock         sync.Mutex
+}
+
+func (t *AlphaGenerator) getAndIncrement() byte {
+	t.lock.Lock()
+	defer t.lock.Unlock()
+	// If we've reached the max value 'z', reset back to 'g'
+	if t.currentAlpha >= 'z' {
+		t.currentAlpha = 'g'
+	}
+	result := t.currentAlpha
+	t.currentAlpha += 1
+	return result
+}
+
+type Connection struct {
+	_default.DefaultConnection
+	alphaGenerator AlphaGenerator
+	messageCodec   spi.MessageCodec
+	configuration  Configuration
+	driverContext  DriverContext
+	tm             *spi.RequestTransactionManager
+
+	connectionId string
+	tracer       *spi.Tracer
+}
+
+func NewConnection(messageCodec spi.MessageCodec, configuration Configuration, driverContext DriverContext, fieldHandler spi.PlcFieldHandler, tm *spi.RequestTransactionManager, options map[string][]string) *Connection {
+	connection := &Connection{
+		alphaGenerator: AlphaGenerator{currentAlpha: 'g'},
+		messageCodec:   messageCodec,
+		configuration:  configuration,
+		driverContext:  driverContext,
+		tm:             tm,
+	}
+	if traceEnabledOption, ok := options["traceEnabled"]; ok {
+		if len(traceEnabledOption) == 1 {
+			connection.tracer = spi.NewTracer(connection.connectionId)
+		}
+	}
+	connection.DefaultConnection = _default.NewDefaultConnection(connection,
+		_default.WithPlcFieldHandler(fieldHandler),
+		_default.WithPlcValueHandler(NewValueHandler()),
+	)
+	return connection
+}
+
+func (m *Connection) GetConnectionId() string {
+	return m.connectionId
+}
+
+func (m *Connection) IsTraceEnabled() bool {
+	return m.tracer != nil
+}
+
+func (m *Connection) GetTracer() *spi.Tracer {
+	return m.tracer
+}
+
+func (m *Connection) GetConnection() plc4go.PlcConnection {
+	return m
+}
+
+func (m *Connection) GetMessageCodec() spi.MessageCodec {
+	return m.messageCodec
+}
+
+func (m *Connection) Connect() <-chan plc4go.PlcConnectionConnectResult {
+	log.Trace().Msg("Connecting")
+	ch := make(chan plc4go.PlcConnectionConnectResult)
+	go func() {
+		// TODO: implement connect logic
+		m.fireConnected(ch)
+	}()
+	return ch
+}
+
+func (m *Connection) fireConnectionError(err error, ch chan<- plc4go.PlcConnectionConnectResult) {
+	if m.driverContext.awaitSetupComplete {
+		ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.Wrap(err, "Error during connection"))
+	} else {
+		log.Error().Err(err).Msg("awaitSetupComplete set to false and we got a error during connect")
+	}
+}
+
+func (m *Connection) fireConnected(ch chan<- plc4go.PlcConnectionConnectResult) {
+	if m.driverContext.awaitSetupComplete {
+		ch <- _default.NewDefaultPlcConnectionConnectResult(m, nil)
+	} else {
+		log.Info().Msg("Successfully connected")
+	}
+	m.SetConnected(true)
+}
+
+func (m *Connection) GetMetadata() apiModel.PlcConnectionMetadata {
+	return _default.DefaultConnectionMetadata{
+		ProvidesReading:     true,
+		ProvidesWriting:     true,
+		ProvidesSubscribing: true,
+		ProvidesBrowsing:    true,
+	}
+}
+
+func (m *Connection) ReadRequestBuilder() apiModel.PlcReadRequestBuilder {
+	return internalModel.NewDefaultPlcReadRequestBuilder(m.GetPlcFieldHandler(), NewReader(&m.alphaGenerator, m.messageCodec, m.tm))
+}
+
+func (m *Connection) WriteRequestBuilder() apiModel.PlcWriteRequestBuilder {
+	return internalModel.NewDefaultPlcWriteRequestBuilder(m.GetPlcFieldHandler(), m.GetPlcValueHandler(), NewWriter(&m.alphaGenerator, m.messageCodec, m.tm))
+}
+
+func (m *Connection) SubscriptionRequestBuilder() apiModel.PlcSubscriptionRequestBuilder {
+	// TODO: where do we get the subscriber from
+	return internalModel.NewDefaultPlcSubscriptionRequestBuilder(m.GetPlcFieldHandler(), m.GetPlcValueHandler(), nil)
+}
+
+func (m *Connection) UnsubscriptionRequestBuilder() apiModel.PlcUnsubscriptionRequestBuilder {
+	// TODO: where do we get the unsubscriber from
+	return nil
+}
+
+func (m *Connection) BrowseRequestBuilder() apiModel.PlcBrowseRequestBuilder {
+	// TODO: where do we get the browser from
+	return internalModel.NewDefaultPlcBrowseRequestBuilder(nil)
+}
+
+func (m *Connection) String() string {
+	return fmt.Sprintf("cbus.Connection")
+}
diff --git a/plc4go/internal/cbus/Driver.go b/plc4go/internal/cbus/Driver.go
new file mode 100644
index 000000000..4fa8674e6
--- /dev/null
+++ b/plc4go/internal/cbus/Driver.go
@@ -0,0 +1,110 @@
+/*
+ * 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
+ *
+ *   https://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 cbus
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	_default "github.com/apache/plc4x/plc4go/internal/spi/default"
+	"github.com/apache/plc4x/plc4go/internal/spi/transports"
+	"github.com/apache/plc4x/plc4go/pkg/api"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+	"net/url"
+)
+
+type Driver struct {
+	_default.DefaultDriver
+	tm                      spi.RequestTransactionManager
+	awaitSetupComplete      bool
+	awaitDisconnectComplete bool
+}
+
+func NewDriver() plc4go.PlcDriver {
+	return &Driver{
+		DefaultDriver:           _default.NewDefaultDriver("c-bus", "Clipsal Bus", "tcp", NewFieldHandler()),
+		tm:                      spi.NewRequestTransactionManager(1),
+		awaitSetupComplete:      true,
+		awaitDisconnectComplete: true,
+	}
+}
+
+func (m *Driver) GetConnection(transportUrl url.URL, transports map[string]transports.Transport, options map[string][]string) <-chan plc4go.PlcConnectionConnectResult {
+	log.Debug().Stringer("transportUrl", &transportUrl).Msgf("Get connection for transport url with %d transport(s) and %d option(s)", len(transports), len(options))
+	// Get the transport specified in the url
+	transport, ok := transports[transportUrl.Scheme]
+	if !ok {
+		log.Error().Stringer("transportUrl", &transportUrl).Msgf("We couldn't find a transport for scheme %s", transportUrl.Scheme)
+		ch := make(chan plc4go.PlcConnectionConnectResult)
+		go func() {
+			ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.Errorf("couldn't find transport for given transport url %#v", transportUrl))
+		}()
+		return ch
+	}
+	// Provide a default-port to the transport, which is used, if the user doesn't provide on in the connection string.
+	options["defaultTcpPort"] = []string{"10010"}
+	// Have the transport create a new transport-instance.
+	transportInstance, err := transport.CreateTransportInstance(transportUrl, options)
+	if err != nil {
+		log.Error().Stringer("transportUrl", &transportUrl).Msgf("We couldn't create a transport instance for port %#v", options["defaultTcpPort"])
+		ch := make(chan plc4go.PlcConnectionConnectResult)
+		go func() {
+			ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.New("couldn't initialize transport configuration for given transport url "+transportUrl.String()))
+		}()
+		return ch
+	}
+
+	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 <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.Wrap(err, "Invalid options"))
+		}()
+		return ch
+	}
+
+	driverContext, err := NewDriverContext(configuration)
+	if err != nil {
+		log.Error().Err(err).Msgf("Invalid options")
+		ch := make(chan plc4go.PlcConnectionConnectResult)
+		go func() {
+			ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.Wrap(err, "Invalid options"))
+		}()
+		return ch
+	}
+	driverContext.awaitSetupComplete = m.awaitSetupComplete
+	driverContext.awaitDisconnectComplete = m.awaitDisconnectComplete
+
+	// Create the new connection
+	connection := NewConnection(codec, configuration, driverContext, m.GetPlcFieldHandler(), &m.tm, options)
+	log.Debug().Msg("created connection, connecting now")
+	return connection.Connect()
+}
+
+func (m *Driver) SetAwaitSetupComplete(awaitComplete bool) {
+	m.awaitSetupComplete = awaitComplete
+}
+
+func (m *Driver) SetAwaitDisconnectComplete(awaitComplete bool) {
+	m.awaitDisconnectComplete = awaitComplete
+}
diff --git a/plc4go/internal/cbus/DriverContext.go b/plc4go/internal/cbus/DriverContext.go
new file mode 100644
index 000000000..2c02a08d6
--- /dev/null
+++ b/plc4go/internal/cbus/DriverContext.go
@@ -0,0 +1,29 @@
+/*
+ * 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
+ *
+ *   https://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 cbus
+
+type DriverContext struct {
+	awaitSetupComplete      bool
+	awaitDisconnectComplete bool
+}
+
+func NewDriverContext(configuration Configuration) (DriverContext, error) {
+	return DriverContext{}, nil
+}
diff --git a/plc4go/internal/cbus/Field.go b/plc4go/internal/cbus/Field.go
new file mode 100644
index 000000000..a846ceb08
--- /dev/null
+++ b/plc4go/internal/cbus/Field.go
@@ -0,0 +1,69 @@
+/*
+ * 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
+ *
+ *   https://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 cbus
+
+import (
+	"fmt"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model"
+)
+
+type PlcField interface {
+	GetApplicationId() readWriteModel.ApplicationId
+}
+
+type plcField struct {
+	NumElements uint16
+}
+
+func NewField(numElements uint16) PlcField {
+	return &plcField{
+		NumElements: numElements,
+	}
+}
+
+func (m plcField) GetAddressString() string {
+	// TODO: implement me
+	return fmt.Sprintf("TODO[%d]", m.NumElements)
+}
+
+func (m plcField) GetTypeName() string {
+	return "TODO"
+}
+
+func (m plcField) GetApplicationId() readWriteModel.ApplicationId {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m plcField) GetQuantity() uint16 {
+	return m.NumElements
+}
+
+func (m plcField) Serialize(writeBuffer utils.WriteBuffer) error {
+	if err := writeBuffer.PushContext("TODO"); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.PopContext("TODO"); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/plc4go/internal/cbus/FieldHandler.go b/plc4go/internal/cbus/FieldHandler.go
new file mode 100644
index 000000000..5b7751823
--- /dev/null
+++ b/plc4go/internal/cbus/FieldHandler.go
@@ -0,0 +1,47 @@
+/*
+ * 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
+ *
+ *   https://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 cbus
+
+import (
+	"github.com/apache/plc4x/plc4go/pkg/api/model"
+	"github.com/pkg/errors"
+)
+
+type FieldType uint8
+
+//go:generate stringer -type FieldType
+const (
+	TODO FieldType = 0x00
+)
+
+func (i FieldType) GetName() string {
+	return i.String()
+}
+
+type FieldHandler struct {
+}
+
+func NewFieldHandler() FieldHandler {
+	return FieldHandler{}
+}
+
+func (m FieldHandler) ParseQuery(query string) (model.PlcField, error) {
+	return nil, errors.Errorf("Unable to parse %s", query)
+}
diff --git a/plc4go/internal/cbus/MessageCodec.go b/plc4go/internal/cbus/MessageCodec.go
new file mode 100644
index 000000000..9a9aab214
--- /dev/null
+++ b/plc4go/internal/cbus/MessageCodec.go
@@ -0,0 +1,155 @@
+/*
+ * 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
+ *
+ *   https://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 cbus
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	"github.com/apache/plc4x/plc4go/internal/spi/default"
+	"github.com/apache/plc4x/plc4go/internal/spi/transports"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	readwriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+	"hash/crc32"
+)
+
+type MessageCodec struct {
+	_default.DefaultCodec
+
+	requestContext  readwriteModel.RequestContext
+	cbusOptions     readwriteModel.CBusOptions
+	lastPackageHash uint32
+	hashEncountered uint
+}
+
+func NewMessageCodec(transportInstance transports.TransportInstance) *MessageCodec {
+	codec := &MessageCodec{
+		requestContext: readwriteModel.NewRequestContext(false, false, false),
+		cbusOptions:    readwriteModel.NewCBusOptions(false, false, false, false, false, false, false, false, false),
+	}
+	codec.DefaultCodec = _default.NewDefaultCodec(codec, transportInstance)
+	return codec
+}
+
+func (m *MessageCodec) GetCodec() spi.MessageCodec {
+	return m
+}
+
+func (m *MessageCodec) Send(message spi.Message) error {
+	log.Trace().Msg("Sending message")
+	// Cast the message to the correct type of struct
+	cbusMessage := message.(readwriteModel.CBusMessage)
+	// Serialize the request
+	wb := utils.NewWriteBufferByteBased()
+	err := cbusMessage.Serialize(wb)
+	if err != nil {
+		return errors.Wrap(err, "error serializing request")
+	}
+
+	// Send it to the PLC
+	err = m.GetTransportInstance().Write(wb.GetBytes())
+	if err != nil {
+		return errors.Wrap(err, "error sending request")
+	}
+	return nil
+}
+
+func (m *MessageCodec) Receive() (spi.Message, error) {
+	log.Trace().Msg("receiving")
+
+	ti := m.GetTransportInstance()
+	readableBytes, err := ti.GetNumReadableBytes()
+	if err != nil {
+		log.Warn().Err(err).Msg("Got error reading")
+		return nil, nil
+	}
+	if readableBytes == 0 {
+		log.Trace().Msg("Nothing to read")
+		return nil, nil
+	}
+	peekedBytes, err := ti.PeekReadableBytes(readableBytes)
+	pciResponse, requestToPci := false, false
+	indexOfCR := -1
+	indexOfLF := -1
+lookingForTheEnd:
+	for i, peekedByte := range peekedBytes {
+		switch peekedByte {
+		case '\r':
+			if indexOfCR >= 0 {
+				// We found the next <cr> so we know we have a package
+				requestToPci = true
+				break lookingForTheEnd
+			}
+			indexOfCR = i
+		case '\n':
+			indexOfLF = i
+			// If we found a <nl> we know definitely that we hit the end of a message
+			break lookingForTheEnd
+		}
+	}
+	if indexOfCR < 0 && indexOfLF >= 0 {
+		// This means that the package is garbage as a lf is always prefixed with a cr
+		log.Debug().Err(err).Msg("Error reading")
+		// TODO: Possibly clean up ...
+		return nil, nil
+	}
+	if indexOfCR+1 == indexOfLF {
+		// This means a <cr> is directly followed by a <lf> which means that we know for sure this is a response
+		pciResponse = true
+	}
+	if !requestToPci && indexOfLF < 0 {
+		// To be sure we might receive that package later we hash the bytes and check if we might receive one
+		hash := crc32.NewIEEE()
+		_, _ = hash.Write(peekedBytes)
+		newPackageHash := hash.Sum32()
+		if newPackageHash == m.lastPackageHash {
+			m.hashEncountered++
+		}
+		m.lastPackageHash = newPackageHash
+		if m.hashEncountered < 9 {
+			return nil, nil
+		} else {
+			// after 90ms we give up finding a lf
+			m.lastPackageHash, m.hashEncountered = 0, 0
+		}
+	}
+	if !pciResponse || !requestToPci {
+		// Apparently we have not found any message yet
+		return nil, nil
+	}
+
+	// Sanity check
+	if pciResponse && requestToPci {
+		panic("Invalid state... Can not be response and request at the same time")
+	}
+
+	read, err := ti.Read(uint32(indexOfCR + 1))
+	if err != nil {
+		panic("Invalid state... If we have peeked that before we should be able to read that now")
+	}
+	rb := utils.NewReadBufferByteBased(read)
+	cBusMessage, err := readwriteModel.CBusMessageParse(rb, pciResponse, m.requestContext, m.cbusOptions, uint16(len(read)))
+	if err != nil {
+		log.Warn().Err(err).Msg("error parsing")
+		// TODO: Possibly clean up ...
+		return nil, nil
+	}
+	return cBusMessage, nil
+}
diff --git a/plc4go/internal/cbus/Reader.go b/plc4go/internal/cbus/Reader.go
new file mode 100644
index 000000000..510cd83f9
--- /dev/null
+++ b/plc4go/internal/cbus/Reader.go
@@ -0,0 +1,55 @@
+/*
+ * 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
+ *
+ *   https://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 cbus
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	plc4goModel "github.com/apache/plc4x/plc4go/internal/spi/model"
+	"github.com/apache/plc4x/plc4go/pkg/api/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+)
+
+type Reader struct {
+	alphaGenerator *AlphaGenerator
+	messageCodec   spi.MessageCodec
+	tm             *spi.RequestTransactionManager
+}
+
+func NewReader(tpduGenerator *AlphaGenerator, messageCodec spi.MessageCodec, tm *spi.RequestTransactionManager) *Reader {
+	return &Reader{
+		alphaGenerator: tpduGenerator,
+		messageCodec:   messageCodec,
+		tm:             tm,
+	}
+}
+
+func (m *Reader) Read(readRequest model.PlcReadRequest) <-chan model.PlcReadRequestResult {
+	log.Trace().Msg("Reading")
+	result := make(chan model.PlcReadRequestResult)
+	go func() {
+		result <- &plc4goModel.DefaultPlcReadRequestResult{
+			Request:  readRequest,
+			Response: nil,
+			Err:      errors.New("Not yet implemented"),
+		}
+	}()
+	return result
+}
diff --git a/plc4go/internal/cbus/ValueHandler.go b/plc4go/internal/cbus/ValueHandler.go
new file mode 100644
index 000000000..f95d569fb
--- /dev/null
+++ b/plc4go/internal/cbus/ValueHandler.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
+ *
+ *   https://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 cbus
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi/values"
+)
+
+type ValueHandler struct {
+	values.IEC61131ValueHandler
+}
+
+func NewValueHandler() ValueHandler {
+	return ValueHandler{}
+}
diff --git a/plc4go/internal/cbus/Writer.go b/plc4go/internal/cbus/Writer.go
new file mode 100644
index 000000000..496f87b6f
--- /dev/null
+++ b/plc4go/internal/cbus/Writer.go
@@ -0,0 +1,53 @@
+/*
+ * 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
+ *
+ *   https://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 cbus
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	plc4goModel "github.com/apache/plc4x/plc4go/internal/spi/model"
+	"github.com/apache/plc4x/plc4go/pkg/api/model"
+	"github.com/pkg/errors"
+)
+
+type Writer struct {
+	alphaGenerator *AlphaGenerator
+	messageCodec   spi.MessageCodec
+	tm             *spi.RequestTransactionManager
+}
+
+func NewWriter(tpduGenerator *AlphaGenerator, messageCodec spi.MessageCodec, tm *spi.RequestTransactionManager) Writer {
+	return Writer{
+		alphaGenerator: tpduGenerator,
+		messageCodec:   messageCodec,
+		tm:             tm,
+	}
+}
+
+func (m Writer) Write(writeRequest model.PlcWriteRequest) <-chan model.PlcWriteRequestResult {
+	result := make(chan model.PlcWriteRequestResult)
+	go func() {
+		result <- &plc4goModel.DefaultPlcWriteRequestResult{
+			Request:  writeRequest,
+			Response: nil,
+			Err:      errors.New("Not yet implemented"),
+		}
+	}()
+	return result
+}
diff --git a/plc4go/internal/cbus/fieldtype_string.go b/plc4go/internal/cbus/fieldtype_string.go
new file mode 100644
index 000000000..fbbc9d338
--- /dev/null
+++ b/plc4go/internal/cbus/fieldtype_string.go
@@ -0,0 +1,40 @@
+// Licensed to 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. Apache Software Foundation (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.
+
+// Code generated by "stringer -type FieldType"; DO NOT EDIT.
+
+package cbus
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[TODO-0]
+}
+
+const _FieldType_name = "TODO"
+
+var _FieldType_index = [...]uint8{0, 4}
+
+func (i FieldType) String() string {
+	if i >= FieldType(len(_FieldType_index)-1) {
+		return "FieldType(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _FieldType_name[_FieldType_index[i]:_FieldType_index[i+1]]
+}
diff --git a/plc4go/pkg/api/drivers/drivers.go b/plc4go/pkg/api/drivers/drivers.go
index 032cbdb50..011a0ba8f 100644
--- a/plc4go/pkg/api/drivers/drivers.go
+++ b/plc4go/pkg/api/drivers/drivers.go
@@ -22,6 +22,7 @@ package drivers
 import (
 	"github.com/apache/plc4x/plc4go/internal/ads"
 	"github.com/apache/plc4x/plc4go/internal/bacnetip"
+	"github.com/apache/plc4x/plc4go/internal/cbus"
 	"github.com/apache/plc4x/plc4go/internal/eip"
 	"github.com/apache/plc4x/plc4go/internal/knxnetip"
 	modbus2 "github.com/apache/plc4x/plc4go/internal/modbus"
@@ -40,6 +41,11 @@ func RegisterBacnetDriver(driverManager plc4go.PlcDriverManager) {
 	transports.RegisterUdpTransport(driverManager)
 }
 
+func RegisterCBusDriver(driverManager plc4go.PlcDriverManager) {
+	driverManager.RegisterDriver(cbus.NewDriver())
+	transports.RegisterTcpTransport(driverManager)
+}
+
 func RegisterEipDriver(driverManager plc4go.PlcDriverManager) {
 	driverManager.RegisterDriver(eip.NewDriver())
 	transports.RegisterTcpTransport(driverManager)
diff --git a/plc4go/pom.xml b/plc4go/pom.xml
index e0f82aaf8..a066ad94f 100644
--- a/plc4go/pom.xml
+++ b/plc4go/pom.xml
@@ -441,7 +441,7 @@
                 <flag>Apache Software Foundation (ASF)</flag>
               </buildFlags>
               <packages>
-                <package>internal/s7/fieldtype_string.go</package>
+                <package>internal/cbus/fieldtype_string.go</package>
               </packages>
             </configuration>
           </execution>
@@ -451,6 +451,23 @@
             <goals>
               <goal>custom</goal>
             </goals>
+            <configuration>
+              <exec>go-licenser</exec>
+              <customCommand>-licensor</customCommand>
+              <buildFlags>
+                <flag>Apache Software Foundation (ASF)</flag>
+              </buildFlags>
+              <packages>
+                <package>internal/s7/fieldtype_string.go</package>
+              </packages>
+            </configuration>
+          </execution>
+          <execution>
+            <id>add-license5</id>
+            <phase>process-sources</phase>
+            <goals>
+              <goal>custom</goal>
+            </goals>
             <configuration>
               <exec>go-licenser</exec>
               <customCommand>-licensor</customCommand>
diff --git a/plc4j/drivers/c-bus/src/test/java/org/apache/plc4x/java/cbus/RandomPackagesTest.java b/plc4j/drivers/c-bus/src/test/java/org/apache/plc4x/java/cbus/RandomPackagesTest.java
index 41a7e7be8..3fd6ce295 100644
--- a/plc4j/drivers/c-bus/src/test/java/org/apache/plc4x/java/cbus/RandomPackagesTest.java
+++ b/plc4j/drivers/c-bus/src/test/java/org/apache/plc4x/java/cbus/RandomPackagesTest.java
@@ -134,7 +134,6 @@ public class RandomPackagesTest {
         CBusMessage msg = CBusMessage.staticParse(readBufferByteBased, false, requestContext, cBusOptions, bytes.length);
         assertThat(msg).isNotNull();
         System.out.println(msg);
-        CBusMessageToServer messageToServer = (CBusMessageToServer) msg;
         CALData calData = ((RequestObsolete) ((CBusMessageToServer) msg).getRequest()).getCalData();
         System.out.println(calData);
         assertMessageMatches(bytes, msg);