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);