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 17:29:57 UTC

[plc4x] branch develop updated (38a8bdf4e -> 8cbe0ee22)

This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a change to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git


    from 38a8bdf4e feat(plc4go/cbus): progress on field handling
     new 01e6c6d0f fix(plc4go/s7): fixed serialize of PlcStringField
     new 8cbe0ee22 fix(plc4go/cbus): T-0 implementation for STATUS, CAL_RECALL, CAL_IDENTIFY, CAL_GETSTATUS

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 plc4go/internal/cbus/Connection.go                 |  29 ---
 plc4go/internal/cbus/Driver.go                     |   4 +-
 plc4go/internal/cbus/Field.go                      | 253 ++++++++++++++++++---
 plc4go/internal/cbus/FieldHandler.go               | 188 +++++++++++++--
 plc4go/internal/cbus/Reader.go                     | 197 +++++++++++++++-
 plc4go/internal/cbus/fieldtype_string.go           |   8 +-
 plc4go/internal/s7/Field.go                        |   2 +-
 .../readwrite/model/StatusRequestBinaryState.go    |  25 +-
 .../model/StatusRequestBinaryStateDeprecated.go    |  25 +-
 .../cbus/readwrite/model/StatusRequestLevel.go     |  25 +-
 .../tests/drivers/tests/manual_cbus_driver_test.go |   3 +
 .../src/main/resources/protocols/cbus/c-bus.mspec  |  22 +-
 12 files changed, 669 insertions(+), 112 deletions(-)


[plc4x] 02/02: fix(plc4go/cbus): T-0 implementation for STATUS, CAL_RECALL, CAL_IDENTIFY, CAL_GETSTATUS

Posted by sr...@apache.org.
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

commit 8cbe0ee22ed610e66677f5c3f758300038e6d38f
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Tue Jul 26 19:29:49 2022 +0200

    fix(plc4go/cbus): T-0 implementation for STATUS, CAL_RECALL, CAL_IDENTIFY, CAL_GETSTATUS
---
 plc4go/internal/cbus/Connection.go                 |  29 ---
 plc4go/internal/cbus/Driver.go                     |   4 +-
 plc4go/internal/cbus/Field.go                      | 253 ++++++++++++++++++---
 plc4go/internal/cbus/FieldHandler.go               | 188 +++++++++++++--
 plc4go/internal/cbus/Reader.go                     | 197 +++++++++++++++-
 plc4go/internal/cbus/fieldtype_string.go           |   8 +-
 .../readwrite/model/StatusRequestBinaryState.go    |  25 +-
 .../model/StatusRequestBinaryStateDeprecated.go    |  25 +-
 .../cbus/readwrite/model/StatusRequestLevel.go     |  25 +-
 .../tests/drivers/tests/manual_cbus_driver_test.go |   3 +
 .../src/main/resources/protocols/cbus/c-bus.mspec  |  22 +-
 11 files changed, 668 insertions(+), 111 deletions(-)

diff --git a/plc4go/internal/cbus/Connection.go b/plc4go/internal/cbus/Connection.go
index 6370704d4..c3e079622 100644
--- a/plc4go/internal/cbus/Connection.go
+++ b/plc4go/internal/cbus/Connection.go
@@ -26,8 +26,6 @@ import (
 	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"
 )
 
@@ -100,33 +98,6 @@ 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,
diff --git a/plc4go/internal/cbus/Driver.go b/plc4go/internal/cbus/Driver.go
index 4fa8674e6..00ded8e73 100644
--- a/plc4go/internal/cbus/Driver.go
+++ b/plc4go/internal/cbus/Driver.go
@@ -24,9 +24,11 @@ import (
 	_default "github.com/apache/plc4x/plc4go/internal/spi/default"
 	"github.com/apache/plc4x/plc4go/internal/spi/transports"
 	"github.com/apache/plc4x/plc4go/pkg/api"
+	readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model"
 	"github.com/pkg/errors"
 	"github.com/rs/zerolog/log"
 	"net/url"
+	"strconv"
 )
 
 type Driver struct {
@@ -58,7 +60,7 @@ func (m *Driver) GetConnection(transportUrl url.URL, transports map[string]trans
 		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"}
+	options["defaultTcpPort"] = []string{strconv.FormatUint(uint64(readWriteModel.CBusConstants_CBUSTCPDEFAULTPORT), 10)}
 	// Have the transport create a new transport-instance.
 	transportInstance, err := transport.CreateTransportInstance(transportUrl, options)
 	if err != nil {
diff --git a/plc4go/internal/cbus/Field.go b/plc4go/internal/cbus/Field.go
index 619b0c067..448a43c14 100644
--- a/plc4go/internal/cbus/Field.go
+++ b/plc4go/internal/cbus/Field.go
@@ -37,38 +37,116 @@ const (
 type StatusField interface {
 	model.PlcField
 	GetStatusRequestType() StatusRequestType
-	GetApplicationId() readWriteModel.ApplicationId
+	GetStartingGroupAddressLabel() *byte
+	GetApplication() readWriteModel.ApplicationIdContainer
 }
 
-func NewStatusField(statusRequestType StatusRequestType, level *byte, applicationId readWriteModel.ApplicationId, numElements uint16) StatusField {
+func NewStatusField(statusRequestType StatusRequestType, startingGroupAddressLabel *byte, application readWriteModel.ApplicationIdContainer, numElements uint16) StatusField {
 	return &statusField{
-		fieldType:         STATUS,
-		statusRequestType: statusRequestType,
-		applicationId:     applicationId,
-		numElements:       numElements,
+		fieldType:                 STATUS,
+		startingGroupAddressLabel: startingGroupAddressLabel,
+		statusRequestType:         statusRequestType,
+		application:               application,
+		numElements:               numElements,
 	}
 }
 
-// CALField can be used to get device/network management fields
-type CALField interface {
+// CALRecallField can be used to get device/network management fields
+type CALRecallField interface {
 	model.PlcField
+	GetParameter() readWriteModel.Parameter
+	GetCount() uint8
 }
 
-func NewCALField(numElements uint16) CALField {
-	return &calField{
-		fieldType:   CAL,
+func NewCALRecallField(unitAddress readWriteModel.UnitAddress, parameter readWriteModel.Parameter, count uint8, numElements uint16) CALRecallField {
+	return &calRecallField{
+		calField:    calField{unitAddress: unitAddress},
+		fieldType:   CAL_RECALL,
+		parameter:   parameter,
+		count:       count,
 		numElements: numElements,
 	}
 }
 
+// CALIdentifyField can be used to get device/network management fields
+type CALIdentifyField interface {
+	model.PlcField
+	GetAttribute() readWriteModel.Attribute
+}
+
+func NewCALIdentifyField(unitAddress readWriteModel.UnitAddress, attribute readWriteModel.Attribute, numElements uint16) CALIdentifyField {
+	return &calIdentifyField{
+		calField:    calField{unitAddress: unitAddress},
+		fieldType:   CAL_IDENTIFY,
+		attribute:   attribute,
+		numElements: numElements,
+	}
+}
+
+// CALGetstatusField can be used to get device/network management fields
+type CALGetstatusField interface {
+	model.PlcField
+	GetParameter() readWriteModel.Parameter
+	GetCount() uint8
+}
+
+func NewCALGetstatusField(unitAddress readWriteModel.UnitAddress, parameter readWriteModel.Parameter, count uint8, numElements uint16) CALGetstatusField {
+	return &calGetstatusField{
+		calField:    calField{unitAddress: unitAddress},
+		fieldType:   CAL_RECALL,
+		parameter:   parameter,
+		count:       count,
+		numElements: numElements,
+	}
+}
+
+///////////////////////////////////////
+///////////////////////////////////////
+//
+// Internal section
+//
+
 type statusField struct {
-	fieldType         FieldType
-	statusRequestType StatusRequestType
-	level             *byte
-	applicationId     readWriteModel.ApplicationId
-	numElements       uint16
+	fieldType                 FieldType
+	statusRequestType         StatusRequestType
+	startingGroupAddressLabel *byte
+	application               readWriteModel.ApplicationIdContainer
+	numElements               uint16
+}
+
+type calField struct {
+	unitAddress readWriteModel.UnitAddress
+}
+
+type calRecallField struct {
+	calField
+	fieldType   FieldType
+	parameter   readWriteModel.Parameter
+	count       uint8
+	numElements uint16
+}
+
+type calIdentifyField struct {
+	calField
+	fieldType   FieldType
+	attribute   readWriteModel.Attribute
+	numElements uint16
+}
+
+type calGetstatusField struct {
+	calField
+	fieldType   FieldType
+	parameter   readWriteModel.Parameter
+	count       uint8
+	numElements uint16
 }
 
+//
+// Internal section
+//
+///////////////////////////////////////
+///////////////////////////////////////
+
 func (m statusField) GetAddressString() string {
 	return fmt.Sprintf("%d[%d]", m.fieldType, m.numElements)
 }
@@ -77,8 +155,12 @@ func (m statusField) GetStatusRequestType() StatusRequestType {
 	return m.statusRequestType
 }
 
-func (m statusField) GetApplicationId() readWriteModel.ApplicationId {
-	return m.applicationId
+func (m statusField) GetStartingGroupAddressLabel() *byte {
+	return m.startingGroupAddressLabel
+}
+
+func (m statusField) GetApplication() readWriteModel.ApplicationIdContainer {
+	return m.application
 }
 
 func (m statusField) GetTypeName() string {
@@ -89,28 +171,147 @@ func (m statusField) GetQuantity() uint16 {
 	return m.numElements
 }
 
-type calField struct {
-	fieldType   FieldType
-	numElements uint16
+func (m statusField) Serialize(writeBuffer utils.WriteBuffer) error {
+	if err := writeBuffer.PushContext(m.fieldType.GetName()); err != nil {
+		return err
+	}
+
+	// TODO: add string representation
+	if err := writeBuffer.WriteUint8("statusRequestType", 8, uint8(m.statusRequestType)); err != nil {
+		return err
+	}
+	if m.startingGroupAddressLabel != nil {
+		if err := writeBuffer.WriteUint8("startingGroupAddressLabel", 8, *m.startingGroupAddressLabel); err != nil {
+			return err
+		}
+	}
+	if err := writeBuffer.WriteUint8("application", 8, uint8(m.application), utils.WithAdditionalStringRepresentation(m.application.String())); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.PopContext(m.fieldType.GetName()); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (m calField) Serialize(writeBuffer utils.WriteBuffer) error {
+	return m.unitAddress.Serialize(writeBuffer)
+}
+
+func (m calRecallField) GetParameter() readWriteModel.Parameter {
+	return m.parameter
 }
 
-func (m calField) GetAddressString() string {
+func (m calRecallField) GetCount() uint8 {
+	return m.count
+}
+
+func (m calRecallField) GetAddressString() string {
 	return fmt.Sprintf("%d[%d]", m.fieldType, m.numElements)
 }
 
-func (m calField) GetTypeName() string {
-	return CAL.GetName()
+func (m calRecallField) GetTypeName() string {
+	return m.fieldType.GetName()
 }
 
-func (m calField) GetQuantity() uint16 {
+func (m calRecallField) GetQuantity() uint16 {
 	return m.numElements
 }
 
-func (m calField) Serialize(writeBuffer utils.WriteBuffer) error {
+func (m calRecallField) Serialize(writeBuffer utils.WriteBuffer) error {
+	if err := writeBuffer.PushContext(m.fieldType.GetName()); err != nil {
+		return err
+	}
+
+	if err := m.calField.Serialize(writeBuffer); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.WriteUint8("parameter", 8, uint8(m.parameter), utils.WithAdditionalStringRepresentation(m.parameter.String())); err != nil {
+		return err
+	}
+	if err := writeBuffer.WriteUint8("count", 8, m.count); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.PopContext(m.fieldType.GetName()); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (c calIdentifyField) GetAttribute() readWriteModel.Attribute {
+	return c.attribute
+}
+
+func (c calIdentifyField) GetAddressString() string {
+	return fmt.Sprintf("%d[%d]", c.fieldType, c.numElements)
+}
+
+func (c calIdentifyField) GetTypeName() string {
+	return c.fieldType.GetName()
+}
+
+func (c calIdentifyField) GetQuantity() uint16 {
+	return c.numElements
+}
+
+func (m calIdentifyField) Serialize(writeBuffer utils.WriteBuffer) error {
 	if err := writeBuffer.PushContext(m.fieldType.GetName()); err != nil {
 		return err
 	}
 
+	if err := m.calField.Serialize(writeBuffer); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.WriteUint8("attribute", 8, uint8(m.attribute), utils.WithAdditionalStringRepresentation(m.attribute.String())); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.PopContext(m.fieldType.GetName()); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (m calGetstatusField) GetParameter() readWriteModel.Parameter {
+	return m.parameter
+}
+
+func (m calGetstatusField) GetCount() uint8 {
+	return m.count
+}
+
+func (c calGetstatusField) GetAddressString() string {
+	return fmt.Sprintf("%d[%d]", c.fieldType, c.numElements)
+}
+
+func (c calGetstatusField) GetTypeName() string {
+	return c.fieldType.GetName()
+}
+
+func (c calGetstatusField) GetQuantity() uint16 {
+	return c.numElements
+}
+
+func (m calGetstatusField) Serialize(writeBuffer utils.WriteBuffer) error {
+	if err := writeBuffer.PushContext(m.fieldType.GetName()); err != nil {
+		return err
+	}
+
+	if err := m.calField.Serialize(writeBuffer); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.WriteUint8("parameter", 8, uint8(m.parameter), utils.WithAdditionalStringRepresentation(m.parameter.String())); err != nil {
+		return err
+	}
+	if err := writeBuffer.WriteUint8("count", 8, m.count); err != nil {
+		return err
+	}
+
 	if err := writeBuffer.PopContext(m.fieldType.GetName()); err != nil {
 		return err
 	}
diff --git a/plc4go/internal/cbus/FieldHandler.go b/plc4go/internal/cbus/FieldHandler.go
index 5e79ea2e8..d4192fe78 100644
--- a/plc4go/internal/cbus/FieldHandler.go
+++ b/plc4go/internal/cbus/FieldHandler.go
@@ -35,7 +35,9 @@ type FieldType uint8
 //go:generate stringer -type FieldType
 const (
 	STATUS FieldType = iota
-	CAL
+	CAL_RECALL
+	CAL_IDENTIFY
+	CAL_GETSTATUS
 )
 
 func (i FieldType) GetName() string {
@@ -49,32 +51,32 @@ type FieldHandler struct {
 
 func NewFieldHandler() FieldHandler {
 	return FieldHandler{
-		statusRequestPattern: regexp.MustCompile(`^status/(?P<statusRequestType>(?P<binary>binary)|level=0x(?P<level>00|20|40|60|80|A0|C0|E0))/(?P<applicationId>.*)`),
-		calPattern:           regexp.MustCompile(`^cal/(?P<calType>recall=\[(?P<recallParamNo>[\w\d]+),(?P<recallCount>\d+)]|identify=\[(?P<identifyAttribute>[\w\d]+)]|getstatus=\[(?P<getstatusParamNo>[\w\d]+),(?P<getstatusCount>\d+)])`),
+		statusRequestPattern: regexp.MustCompile(`^status/(?P<statusRequestType>(?P<binary>binary)|level=0x(?P<startingGroupAddressLabel>00|20|40|60|80|A0|C0|E0))/(?P<application>.*)`),
+		calPattern:           regexp.MustCompile(`^cal/(?P<unitAddress>.*)/(?P<calType>recall=\[(?P<recallParamNo>[\w\d]+), ?(?P<recallCount>\d+)]|identify=\[(?P<identifyAttribute>[\w\d]+)]|getstatus=\[(?P<getstatusParamNo>[\w\d]+), ?(?P<getstatusCount>\d+)])`),
 	}
 }
 
 func (m FieldHandler) ParseQuery(query string) (model.PlcField, error) {
 	if match := utils.GetSubgroupMatches(m.statusRequestPattern, query); match != nil {
-		var level *byte
+		var startingGroupAddressLabel *byte
 		var statusRequestType StatusRequestType
 		statusRequestArgument := match["statusRequestType"]
 		if statusRequestArgument != "" {
 			if match["binary"] != "" {
 				statusRequestType = StatusRequestTypeBinaryState
-			} else if levelArgument := match["level"]; levelArgument != "" {
+			} else if levelArgument := match["startingGroupAddressLabel"]; levelArgument != "" {
 				statusRequestType = StatusRequestTypeLevel
 				decodedHex, _ := hex.DecodeString(match["level"])
 				if len(decodedHex) != 1 {
 					panic("invalid state. Should have exactly 1")
 				}
-				level = &decodedHex[0]
+				startingGroupAddressLabel = &decodedHex[0]
 			} else {
 				return nil, errors.Errorf("Unknown statusRequestType%s", statusRequestArgument)
 			}
 		}
-		var applicationId readWriteModel.ApplicationId
-		applicationIdArgument := match["applicationId"]
+		var application readWriteModel.ApplicationIdContainer
+		applicationIdArgument := match["application"]
 		if strings.HasPrefix(applicationIdArgument, "0x") {
 			decodedHex, err := hex.DecodeString(applicationIdArgument[2:])
 			if err != nil {
@@ -83,29 +85,179 @@ func (m FieldHandler) ParseQuery(query string) (model.PlcField, error) {
 			if len(decodedHex) != 1 {
 				return nil, errors.Errorf("Hex must be exatly one byte")
 			}
-			applicationId = readWriteModel.ApplicationId(decodedHex[0])
+			application = readWriteModel.ApplicationIdContainer(decodedHex[0])
 		} else {
 			atoi, err := strconv.ParseUint(applicationIdArgument, 10, 8)
 			if err != nil {
-				applicationId = readWriteModel.ApplicationId(atoi)
+				application = readWriteModel.ApplicationIdContainer(atoi)
 			} else {
-				applicationIdByName, ok := readWriteModel.ApplicationIdByName(applicationIdArgument)
-				if !ok {
-					return nil, errors.Errorf("Unknown applicationId%s", applicationIdArgument)
+				// We try first the application id
+				applicationId, ok := readWriteModel.ApplicationIdByName(applicationIdArgument)
+				if ok {
+					switch applicationId {
+					case readWriteModel.ApplicationId_TEMPERATURE_BROADCAST:
+						application = readWriteModel.ApplicationIdContainer_TEMPERATURE_BROADCAST_19
+					case readWriteModel.ApplicationId_ROOM_CONTROL_SYSTEM:
+						application = readWriteModel.ApplicationIdContainer_ROOM_CONTROL_SYSTEM_26
+					case readWriteModel.ApplicationId_LIGHTING:
+						application = readWriteModel.ApplicationIdContainer_LIGHTING_38
+					case readWriteModel.ApplicationId_VENTILATION:
+						application = readWriteModel.ApplicationIdContainer_VENTILATION_70
+					case readWriteModel.ApplicationId_IRRIGATION_CONTROL:
+						application = readWriteModel.ApplicationIdContainer_IRRIGATION_CONTROL_71
+					case readWriteModel.ApplicationId_POOLS_SPAS_PONDS_FOUNTAINS_CONTROL:
+						application = readWriteModel.ApplicationIdContainer_POOLS_SPAS_PONDS_FOUNTAINS_CONTROL_72
+					case readWriteModel.ApplicationId_HEATING:
+						application = readWriteModel.ApplicationIdContainer_HEATING_88
+					case readWriteModel.ApplicationId_AIR_CONDITIONING:
+						application = readWriteModel.ApplicationIdContainer_AIR_CONDITIONING_AC
+					case readWriteModel.ApplicationId_TRIGGER_CONTROL:
+						application = readWriteModel.ApplicationIdContainer_TRIGGER_CONTROL_CA
+					case readWriteModel.ApplicationId_ENABLE_CONTROL:
+						application = readWriteModel.ApplicationIdContainer_ENABLE_CONTROL_CB
+					case readWriteModel.ApplicationId_AUDIO_AND_VIDEO:
+						application = readWriteModel.ApplicationIdContainer_AUDIO_AND_VIDEO_CD
+					case readWriteModel.ApplicationId_SECURITY:
+						application = readWriteModel.ApplicationIdContainer_SECURITY_D0
+					case readWriteModel.ApplicationId_METERING:
+						application = readWriteModel.ApplicationIdContainer_METERING_D1
+					case readWriteModel.ApplicationId_ACCESS_CONTROL:
+						application = readWriteModel.ApplicationIdContainer_ACCESS_CONTROL_D5
+					case readWriteModel.ApplicationId_CLOCK_AND_TIMEKEEPING:
+						application = readWriteModel.ApplicationIdContainer_CLOCK_AND_TIMEKEEPING_DF
+					case readWriteModel.ApplicationId_TELEPHONY_STATUS_AND_CONTROL:
+						application = readWriteModel.ApplicationIdContainer_TELEPHONY_STATUS_AND_CONTROL_E0
+					case readWriteModel.ApplicationId_MEASUREMENT:
+						application = readWriteModel.ApplicationIdContainer_MEASUREMENT_E4
+					case readWriteModel.ApplicationId_TESTING:
+						application = readWriteModel.ApplicationIdContainer_TESTING_FA
+					case readWriteModel.ApplicationId_MEDIA_TRANSPORT_CONTROL:
+						application = readWriteModel.ApplicationIdContainer_MEDIA_TRANSPORT_CONTROL_C0
+					case readWriteModel.ApplicationId_ERROR_REPORTING:
+						application = readWriteModel.ApplicationIdContainer_ERROR_REPORTING_CE
+					case readWriteModel.ApplicationId_HVAC_ACTUATOR:
+					default:
+						return nil, errors.Errorf("%s can't be used directly... select proper application id container", applicationId)
+					}
+				} else {
+					applicationIdByName, ok := readWriteModel.ApplicationIdContainerByName(applicationIdArgument)
+					if !ok {
+						return nil, errors.Errorf("Unknown applicationId%s", applicationIdArgument)
+					}
+					application = applicationIdByName
 				}
-				applicationId = applicationIdByName
 			}
 		}
-		return NewStatusField(statusRequestType, level, applicationId, 1), nil
+		return NewStatusField(statusRequestType, startingGroupAddressLabel, application, 1), nil
 	} else if match := utils.GetSubgroupMatches(m.calPattern, query); match != nil {
+		var unitAddress readWriteModel.UnitAddress
+		unitAddressArgument := match["unitAddress"]
+		if strings.HasPrefix(unitAddressArgument, "0x") {
+			decodedHex, err := hex.DecodeString(unitAddressArgument[2:])
+			if err != nil {
+				return nil, errors.Wrap(err, "Not a valid hex")
+			}
+			if len(decodedHex) != 1 {
+				return nil, errors.Errorf("Hex must be exatly one byte")
+			}
+			unitAddress = readWriteModel.NewUnitAddress(decodedHex[0])
+		} else {
+			atoi, err := strconv.ParseUint(unitAddressArgument, 10, 8)
+			if err != nil {
+				return nil, errors.Errorf("Unknown unit address %s", unitAddressArgument)
+			}
+			unitAddress = readWriteModel.NewUnitAddress(byte(atoi))
+		}
+
 		calTypeArgument := match["calType"]
 		switch {
 		case strings.HasPrefix(calTypeArgument, "recall="):
-			panic("Implement me ")
+			var recalParamNo readWriteModel.Parameter
+			recallParamNoArgument := match["recallParamNo"]
+			if strings.HasPrefix(recallParamNoArgument, "0x") {
+				decodedHex, err := hex.DecodeString(recallParamNoArgument[2:])
+				if err != nil {
+					return nil, errors.Wrap(err, "Not a valid hex")
+				}
+				if len(decodedHex) != 1 {
+					return nil, errors.Errorf("Hex must be exatly one byte")
+				}
+				recalParamNo = readWriteModel.Parameter(decodedHex[0])
+			} else {
+				atoi, err := strconv.ParseUint(recallParamNoArgument, 10, 8)
+				if err != nil {
+					recalParamNo = readWriteModel.Parameter(atoi)
+				} else {
+					parameterByName, ok := readWriteModel.ParameterByName(recallParamNoArgument)
+					if !ok {
+						return nil, errors.Errorf("Unknown recallParamNo %s", recallParamNoArgument)
+					}
+					recalParamNo = parameterByName
+				}
+			}
+			var count uint8
+			atoi, err := strconv.ParseUint(match["recallCount"], 10, 8)
+			if err != nil {
+				return nil, errors.Wrap(err, "recallCount not a valid number")
+			}
+			count = uint8(atoi)
+			return NewCALRecallField(unitAddress, recalParamNo, count, 1), nil
 		case strings.HasPrefix(calTypeArgument, "identify="):
-			panic("Implement me ")
+			var attribute readWriteModel.Attribute
+			attributeArgument := match["identifyAttribute"]
+			if strings.HasPrefix(attributeArgument, "0x") {
+				decodedHex, err := hex.DecodeString(attributeArgument[2:])
+				if err != nil {
+					return nil, errors.Wrap(err, "Not a valid hex")
+				}
+				if len(decodedHex) != 1 {
+					return nil, errors.Errorf("Hex must be exatly one byte")
+				}
+				attribute = readWriteModel.Attribute(decodedHex[0])
+			} else {
+				atoi, err := strconv.ParseUint(attributeArgument, 10, 8)
+				if err != nil {
+					attribute = readWriteModel.Attribute(atoi)
+				} else {
+					parameterByName, ok := readWriteModel.AttributeByName(attributeArgument)
+					if !ok {
+						return nil, errors.Errorf("Unknown attributeArgument %s", attributeArgument)
+					}
+					attribute = parameterByName
+				}
+			}
+			return NewCALIdentifyField(unitAddress, attribute, 1), nil
 		case strings.HasPrefix(calTypeArgument, "getstatus="):
-			panic("Implement me ")
+			var recalParamNo readWriteModel.Parameter
+			recallParamNoArgument := match["getstatusParamNo"]
+			if strings.HasPrefix(recallParamNoArgument, "0x") {
+				decodedHex, err := hex.DecodeString(recallParamNoArgument[2:])
+				if err != nil {
+					return nil, errors.Wrap(err, "Not a valid hex")
+				}
+				if len(decodedHex) != 1 {
+					return nil, errors.Errorf("Hex must be exatly one byte")
+				}
+				recalParamNo = readWriteModel.Parameter(decodedHex[0])
+			} else {
+				atoi, err := strconv.ParseUint(recallParamNoArgument, 10, 8)
+				if err != nil {
+					recalParamNo = readWriteModel.Parameter(atoi)
+				} else {
+					parameterByName, ok := readWriteModel.ParameterByName(recallParamNoArgument)
+					if !ok {
+						return nil, errors.Errorf("Unknown getstatusParamNo %s", recallParamNoArgument)
+					}
+					recalParamNo = parameterByName
+				}
+			}
+			var count uint8
+			atoi, err := strconv.ParseUint(match["getstatusCount"], 10, 8)
+			if err != nil {
+				return nil, errors.Wrap(err, "getstatusCount not a valid number")
+			}
+			count = uint8(atoi)
+			return NewCALGetstatusField(unitAddress, recalParamNo, count, 1), nil
 		default:
 			return nil, errors.Errorf("Invalid cal type %s", calTypeArgument)
 		}
diff --git a/plc4go/internal/cbus/Reader.go b/plc4go/internal/cbus/Reader.go
index 510cd83f9..fa48c80bc 100644
--- a/plc4go/internal/cbus/Reader.go
+++ b/plc4go/internal/cbus/Reader.go
@@ -20,11 +20,17 @@
 package cbus
 
 import (
+	"fmt"
 	"github.com/apache/plc4x/plc4go/internal/spi"
 	plc4goModel "github.com/apache/plc4x/plc4go/internal/spi/model"
+	values2 "github.com/apache/plc4x/plc4go/internal/spi/values"
 	"github.com/apache/plc4x/plc4go/pkg/api/model"
+	"github.com/apache/plc4x/plc4go/pkg/api/values"
+	readWriteModel "github.com/apache/plc4x/plc4go/protocols/cbus/readwrite/model"
 	"github.com/pkg/errors"
 	"github.com/rs/zerolog/log"
+	"sync"
+	"time"
 )
 
 type Reader struct {
@@ -45,11 +51,198 @@ func (m *Reader) Read(readRequest model.PlcReadRequest) <-chan model.PlcReadRequ
 	log.Trace().Msg("Reading")
 	result := make(chan model.PlcReadRequestResult)
 	go func() {
+		numFields := len(readRequest.GetFieldNames())
+		if numFields > 20 {
+			result <- &plc4goModel.DefaultPlcReadRequestResult{
+				Request:  readRequest,
+				Response: nil,
+				Err:      errors.New("Only 20 fields can be handled at once"),
+			}
+			return
+		}
+		messages := make(map[string]readWriteModel.CBusMessage)
+		for _, fieldName := range readRequest.GetFieldNames() {
+			field := readRequest.GetField(fieldName)
+			message, err := m.fieldToCBusMessage(field)
+			if err != nil {
+				result <- &plc4goModel.DefaultPlcReadRequestResult{
+					Request:  readRequest,
+					Response: nil,
+					Err:      errors.Wrapf(err, "Error encoding cbus message for field %s", fieldName),
+				}
+				return
+			}
+			messages[fieldName] = message
+		}
+		responseMu := sync.Mutex{}
+		responseCodes := map[string]model.PlcResponseCode{}
+		addResponseCode := func(name string, responseCode model.PlcResponseCode) {
+			responseMu.Lock()
+			defer responseMu.Unlock()
+			responseCodes[name] = responseCode
+		}
+		valueMu := sync.Mutex{}
+		plcValues := map[string]values.PlcValue{}
+		addPlcValue := func(name string, responseCode values.PlcValue) {
+			valueMu.Lock()
+			defer valueMu.Unlock()
+			plcValues[name] = responseCode
+		}
+		for fieldName, messageToSend := range messages {
+			fieldNameCopy := fieldName
+			// Start a new request-transaction (Is ended in the response-handler)
+			requestWasOk := make(chan bool)
+			transaction := m.tm.StartTransaction()
+			transaction.Submit(func() {
+
+				// Send the  over the wire
+				log.Trace().Msg("Send ")
+				if err := m.messageCodec.SendRequest(
+					messageToSend,
+					func(receivedMessage spi.Message) bool {
+						cbusMessage, ok := receivedMessage.(readWriteModel.CBusMessageExactly)
+						if !ok {
+							return false
+						}
+						messageToClient, ok := cbusMessage.(readWriteModel.CBusMessageToClientExactly)
+						if !ok {
+							return false
+						}
+						confirmation, ok := messageToClient.GetReply().(readWriteModel.ReplyOrConfirmationConfirmationExactly)
+						if !ok {
+							return false
+						}
+						return confirmation.GetConfirmation().GetAlpha().GetCharacter() == messageToSend.(readWriteModel.CBusMessageToServer).GetRequest().(readWriteModel.RequestCommand).GetAlpha().GetCharacter()
+					},
+					func(receivedMessage spi.Message) error {
+						// Convert the response into an
+						log.Trace().Msg("convert response to ")
+						cbusMessage := receivedMessage.(readWriteModel.CBusMessage)
+						messageToClient := cbusMessage.(readWriteModel.CBusMessageToClient)
+						confirmation := messageToClient.GetReply().(readWriteModel.ReplyOrConfirmationConfirmationExactly)
+						if !confirmation.GetConfirmation().GetIsSuccess() {
+							var responseCode model.PlcResponseCode
+							switch confirmation.GetConfirmation().GetConfirmationType() {
+							case readWriteModel.ConfirmationType_CONFIRMATION_SUCCESSFUL:
+								responseCode = model.PlcResponseCode_OK
+							case readWriteModel.ConfirmationType_NOT_TRANSMITTED_TO_MANY_RE_TRANSMISSIONS:
+								responseCode = model.PlcResponseCode_REMOTE_ERROR
+							case readWriteModel.ConfirmationType_NOT_TRANSMITTED_CORRUPTION:
+								responseCode = model.PlcResponseCode_INVALID_DATA
+							case readWriteModel.ConfirmationType_NOT_TRANSMITTED_SYNC_LOSS:
+								responseCode = model.PlcResponseCode_REMOTE_BUSY
+							case readWriteModel.ConfirmationType_NOT_TRANSMITTED_TOO_LONG:
+								responseCode = model.PlcResponseCode_INVALID_DATA
+							}
+							addResponseCode(fieldNameCopy, responseCode)
+							return nil
+						}
+
+						// TODO: it could be double confirmed but this is not implemented yet
+						embeddedReply := confirmation.GetEmbeddedReply().(readWriteModel.ReplyOrConfirmationReplyExactly)
+
+						switch reply := embeddedReply.(readWriteModel.ReplyEncodedReply).GetEncodedReply().(type) {
+						case readWriteModel.EncodedReplyStandardFormatStatusReplyExactly:
+							application := reply.GetReply().GetApplication()
+							// TODO: verify application... this should be the same
+							_ = application
+							blockStart := reply.GetReply().GetBlockStart()
+							// TODO: verify application... this should be the same
+							_ = blockStart
+							statusBytes := reply.GetReply().GetStatusBytes()
+							addResponseCode(fieldNameCopy, model.PlcResponseCode_OK)
+							// TODO: how should we serialize that???
+							addPlcValue(fieldNameCopy, values2.NewPlcSTRING(fmt.Sprintf("%s", statusBytes)))
+						case readWriteModel.EncodedReplyExtendedFormatStatusReplyExactly:
+							coding := reply.GetReply().GetCoding()
+							// TODO: verify coding... this should be the same
+							_ = coding
+							application := reply.GetReply().GetApplication()
+							// TODO: verify application... this should be the same
+							_ = application
+							blockStart := reply.GetReply().GetBlockStart()
+							// TODO: verify application... this should be the same
+							_ = blockStart
+							statusBytes := reply.GetReply().GetStatusBytes()
+							addResponseCode(fieldNameCopy, model.PlcResponseCode_OK)
+							// TODO: how should we serialize that???
+							addPlcValue(fieldNameCopy, values2.NewPlcSTRING(fmt.Sprintf("%s", statusBytes)))
+						case readWriteModel.EncodedReplyCALReplyExactly:
+							calData := reply.GetCalReply().GetCalData()
+							addResponseCode(fieldNameCopy, model.PlcResponseCode_OK)
+							// TODO: how should we serialize that???
+							addPlcValue(fieldNameCopy, values2.NewPlcSTRING(fmt.Sprintf("%s", calData)))
+						}
+						return transaction.EndRequest()
+					},
+					func(err error) error {
+						log.Debug().Msgf("Error waiting for field %s", fieldNameCopy)
+						addResponseCode(fieldNameCopy, model.PlcResponseCode_REQUEST_TIMEOUT)
+						return transaction.EndRequest()
+					},
+					time.Second*1); err != nil {
+					log.Debug().Err(err).Msgf("Error sending message for field %s", fieldNameCopy)
+					addResponseCode(fieldNameCopy, model.PlcResponseCode_INTERNAL_ERROR)
+					_ = transaction.EndRequest()
+				}
+			})
+			if !<-requestWasOk {
+				// TODO: if we found a error we can abort
+				break
+			}
+		}
+		readResponse := plc4goModel.NewDefaultPlcReadResponse(readRequest, responseCodes, plcValues)
 		result <- &plc4goModel.DefaultPlcReadRequestResult{
 			Request:  readRequest,
-			Response: nil,
-			Err:      errors.New("Not yet implemented"),
+			Response: readResponse,
 		}
 	}()
 	return result
 }
+
+var defaultRequestContext = readWriteModel.NewRequestContext(false, false, false)
+var defaultOptions = readWriteModel.NewCBusOptions(false, false, false, false, false, false, false, false, false)
+
+func (m *Reader) fieldToCBusMessage(field model.PlcField) (readWriteModel.CBusMessage, error) {
+	switch field := field.(type) {
+	case *statusField:
+		var statusRequest readWriteModel.StatusRequest
+		switch field.statusRequestType {
+		case StatusRequestTypeBinaryState:
+			statusRequest = readWriteModel.NewStatusRequestBinaryState(field.application, 0x7A)
+		case StatusRequestTypeLevel:
+			statusRequest = readWriteModel.NewStatusRequestLevel(field.application, *field.startingGroupAddressLabel, 0x73)
+		}
+		command := readWriteModel.NewCBusPointToMultiPointCommandStatus(statusRequest, byte(field.application), defaultOptions)
+		header := readWriteModel.NewCBusHeader(readWriteModel.PriorityClass_Class4, false, 0, readWriteModel.DestinationAddressType_PointToMultiPoint)
+		cbusCommand := readWriteModel.NewCBusCommandPointToMultiPoint(command, header, defaultOptions)
+		request := readWriteModel.NewRequestCommand(cbusCommand, nil, readWriteModel.NewAlpha(m.alphaGenerator.getAndIncrement()), readWriteModel.RequestType_REQUEST_COMMAND, nil, nil, readWriteModel.RequestType_EMPTY, readWriteModel.NewRequestTermination(), defaultOptions, 0, 0)
+		return readWriteModel.NewCBusMessageToServer(request, defaultRequestContext, defaultOptions, 0), nil
+	case *calRecallField:
+		calData := readWriteModel.NewCALDataRecall(field.parameter, field.count, readWriteModel.CALCommandTypeContainer_CALCommandRecall, nil, defaultRequestContext)
+		//TODO: we need support for bridged commands
+		command := readWriteModel.NewCBusPointToPointCommandDirect(field.unitAddress, 0x0000, calData, defaultOptions)
+		header := readWriteModel.NewCBusHeader(readWriteModel.PriorityClass_Class4, false, 0, readWriteModel.DestinationAddressType_PointToPoint)
+		cbusCommand := readWriteModel.NewCBusCommandPointToPoint(command, header, defaultOptions)
+		request := readWriteModel.NewRequestCommand(cbusCommand, nil, readWriteModel.NewAlpha(m.alphaGenerator.getAndIncrement()), readWriteModel.RequestType_REQUEST_COMMAND, nil, nil, readWriteModel.RequestType_EMPTY, readWriteModel.NewRequestTermination(), defaultOptions, 0, 0)
+		return readWriteModel.NewCBusMessageToServer(request, defaultRequestContext, defaultOptions, 0), nil
+	case *calIdentifyField:
+		calData := readWriteModel.NewCALDataIdentify(field.attribute, readWriteModel.CALCommandTypeContainer_CALCommandIdentify, nil, defaultRequestContext)
+		//TODO: we need support for bridged commands
+		command := readWriteModel.NewCBusPointToPointCommandDirect(field.unitAddress, 0x0000, calData, defaultOptions)
+		header := readWriteModel.NewCBusHeader(readWriteModel.PriorityClass_Class4, false, 0, readWriteModel.DestinationAddressType_PointToPoint)
+		cbusCommand := readWriteModel.NewCBusCommandPointToPoint(command, header, defaultOptions)
+		request := readWriteModel.NewRequestCommand(cbusCommand, nil, readWriteModel.NewAlpha(m.alphaGenerator.getAndIncrement()), readWriteModel.RequestType_REQUEST_COMMAND, nil, nil, readWriteModel.RequestType_EMPTY, readWriteModel.NewRequestTermination(), defaultOptions, 0, 0)
+		return readWriteModel.NewCBusMessageToServer(request, defaultRequestContext, defaultOptions, 0), nil
+	case *calGetstatusField:
+		calData := readWriteModel.NewCALDataGetStatus(field.parameter, field.count, readWriteModel.CALCommandTypeContainer_CALCommandGetStatus, nil, defaultRequestContext)
+		//TODO: we need support for bridged commands
+		command := readWriteModel.NewCBusPointToPointCommandDirect(field.unitAddress, 0x0000, calData, defaultOptions)
+		header := readWriteModel.NewCBusHeader(readWriteModel.PriorityClass_Class4, false, 0, readWriteModel.DestinationAddressType_PointToPoint)
+		cbusCommand := readWriteModel.NewCBusCommandPointToPoint(command, header, defaultOptions)
+		request := readWriteModel.NewRequestCommand(cbusCommand, nil, readWriteModel.NewAlpha(m.alphaGenerator.getAndIncrement()), readWriteModel.RequestType_REQUEST_COMMAND, nil, nil, readWriteModel.RequestType_EMPTY, readWriteModel.NewRequestTermination(), defaultOptions, 0, 0)
+		return readWriteModel.NewCBusMessageToServer(request, defaultRequestContext, defaultOptions, 0), nil
+	default:
+		return nil, errors.Errorf("Unmapped type %T", field)
+	}
+}
diff --git a/plc4go/internal/cbus/fieldtype_string.go b/plc4go/internal/cbus/fieldtype_string.go
index 4c555467a..ec833d764 100644
--- a/plc4go/internal/cbus/fieldtype_string.go
+++ b/plc4go/internal/cbus/fieldtype_string.go
@@ -26,12 +26,14 @@ func _() {
 	// Re-run the stringer command to generate them again.
 	var x [1]struct{}
 	_ = x[STATUS-0]
-	_ = x[CAL-1]
+	_ = x[CAL_RECALL-1]
+	_ = x[CAL_IDENTIFY-2]
+	_ = x[CAL_GETSTATUS-3]
 }
 
-const _FieldType_name = "STATUSCAL"
+const _FieldType_name = "STATUSCAL_RECALLCAL_IDENTIFYCAL_GETSTATUS"
 
-var _FieldType_index = [...]uint8{0, 6, 9}
+var _FieldType_index = [...]uint8{0, 6, 16, 28, 41}
 
 func (i FieldType) String() string {
 	if i >= FieldType(len(_FieldType_index)-1) {
diff --git a/plc4go/protocols/cbus/readwrite/model/StatusRequestBinaryState.go b/plc4go/protocols/cbus/readwrite/model/StatusRequestBinaryState.go
index 99b674411..b434ec1a9 100644
--- a/plc4go/protocols/cbus/readwrite/model/StatusRequestBinaryState.go
+++ b/plc4go/protocols/cbus/readwrite/model/StatusRequestBinaryState.go
@@ -33,7 +33,7 @@ type StatusRequestBinaryState interface {
 	utils.Serializable
 	StatusRequest
 	// GetApplication returns Application (property field)
-	GetApplication() byte
+	GetApplication() ApplicationIdContainer
 }
 
 // StatusRequestBinaryStateExactly can be used when we want exactly this type and not a type which fulfills StatusRequestBinaryState.
@@ -46,7 +46,7 @@ type StatusRequestBinaryStateExactly interface {
 // _StatusRequestBinaryState is the data-structure of this message
 type _StatusRequestBinaryState struct {
 	*_StatusRequest
-	Application byte
+	Application ApplicationIdContainer
 }
 
 ///////////////////////////////////////////////////////////
@@ -72,7 +72,7 @@ func (m *_StatusRequestBinaryState) GetParent() StatusRequest {
 /////////////////////// Accessors for property fields.
 ///////////////////////
 
-func (m *_StatusRequestBinaryState) GetApplication() byte {
+func (m *_StatusRequestBinaryState) GetApplication() ApplicationIdContainer {
 	return m.Application
 }
 
@@ -82,7 +82,7 @@ func (m *_StatusRequestBinaryState) GetApplication() byte {
 ///////////////////////////////////////////////////////////
 
 // NewStatusRequestBinaryState factory function for _StatusRequestBinaryState
-func NewStatusRequestBinaryState(application byte, statusType byte) *_StatusRequestBinaryState {
+func NewStatusRequestBinaryState(application ApplicationIdContainer, statusType byte) *_StatusRequestBinaryState {
 	_result := &_StatusRequestBinaryState{
 		Application:    application,
 		_StatusRequest: NewStatusRequest(statusType),
@@ -153,11 +153,17 @@ func StatusRequestBinaryStateParse(readBuffer utils.ReadBuffer) (StatusRequestBi
 	}
 
 	// Simple Field (application)
-	_application, _applicationErr := readBuffer.ReadByte("application")
+	if pullErr := readBuffer.PullContext("application"); pullErr != nil {
+		return nil, errors.Wrap(pullErr, "Error pulling for application")
+	}
+	_application, _applicationErr := ApplicationIdContainerParse(readBuffer)
 	if _applicationErr != nil {
 		return nil, errors.Wrap(_applicationErr, "Error parsing 'application' field of StatusRequestBinaryState")
 	}
 	application := _application
+	if closeErr := readBuffer.CloseContext("application"); closeErr != nil {
+		return nil, errors.Wrap(closeErr, "Error closing for application")
+	}
 
 	// Reserved Field (Compartmentalized so the "reserved" variable can't leak)
 	{
@@ -203,8 +209,13 @@ func (m *_StatusRequestBinaryState) Serialize(writeBuffer utils.WriteBuffer) err
 		}
 
 		// Simple Field (application)
-		application := byte(m.GetApplication())
-		_applicationErr := writeBuffer.WriteByte("application", (application))
+		if pushErr := writeBuffer.PushContext("application"); pushErr != nil {
+			return errors.Wrap(pushErr, "Error pushing for application")
+		}
+		_applicationErr := writeBuffer.WriteSerializable(m.GetApplication())
+		if popErr := writeBuffer.PopContext("application"); popErr != nil {
+			return errors.Wrap(popErr, "Error popping for application")
+		}
 		if _applicationErr != nil {
 			return errors.Wrap(_applicationErr, "Error serializing 'application' field")
 		}
diff --git a/plc4go/protocols/cbus/readwrite/model/StatusRequestBinaryStateDeprecated.go b/plc4go/protocols/cbus/readwrite/model/StatusRequestBinaryStateDeprecated.go
index 9149f9e12..3ab9ad7b4 100644
--- a/plc4go/protocols/cbus/readwrite/model/StatusRequestBinaryStateDeprecated.go
+++ b/plc4go/protocols/cbus/readwrite/model/StatusRequestBinaryStateDeprecated.go
@@ -33,7 +33,7 @@ type StatusRequestBinaryStateDeprecated interface {
 	utils.Serializable
 	StatusRequest
 	// GetApplication returns Application (property field)
-	GetApplication() byte
+	GetApplication() ApplicationIdContainer
 }
 
 // StatusRequestBinaryStateDeprecatedExactly can be used when we want exactly this type and not a type which fulfills StatusRequestBinaryStateDeprecated.
@@ -46,7 +46,7 @@ type StatusRequestBinaryStateDeprecatedExactly interface {
 // _StatusRequestBinaryStateDeprecated is the data-structure of this message
 type _StatusRequestBinaryStateDeprecated struct {
 	*_StatusRequest
-	Application byte
+	Application ApplicationIdContainer
 }
 
 ///////////////////////////////////////////////////////////
@@ -72,7 +72,7 @@ func (m *_StatusRequestBinaryStateDeprecated) GetParent() StatusRequest {
 /////////////////////// Accessors for property fields.
 ///////////////////////
 
-func (m *_StatusRequestBinaryStateDeprecated) GetApplication() byte {
+func (m *_StatusRequestBinaryStateDeprecated) GetApplication() ApplicationIdContainer {
 	return m.Application
 }
 
@@ -82,7 +82,7 @@ func (m *_StatusRequestBinaryStateDeprecated) GetApplication() byte {
 ///////////////////////////////////////////////////////////
 
 // NewStatusRequestBinaryStateDeprecated factory function for _StatusRequestBinaryStateDeprecated
-func NewStatusRequestBinaryStateDeprecated(application byte, statusType byte) *_StatusRequestBinaryStateDeprecated {
+func NewStatusRequestBinaryStateDeprecated(application ApplicationIdContainer, statusType byte) *_StatusRequestBinaryStateDeprecated {
 	_result := &_StatusRequestBinaryStateDeprecated{
 		Application:    application,
 		_StatusRequest: NewStatusRequest(statusType),
@@ -153,11 +153,17 @@ func StatusRequestBinaryStateDeprecatedParse(readBuffer utils.ReadBuffer) (Statu
 	}
 
 	// Simple Field (application)
-	_application, _applicationErr := readBuffer.ReadByte("application")
+	if pullErr := readBuffer.PullContext("application"); pullErr != nil {
+		return nil, errors.Wrap(pullErr, "Error pulling for application")
+	}
+	_application, _applicationErr := ApplicationIdContainerParse(readBuffer)
 	if _applicationErr != nil {
 		return nil, errors.Wrap(_applicationErr, "Error parsing 'application' field of StatusRequestBinaryStateDeprecated")
 	}
 	application := _application
+	if closeErr := readBuffer.CloseContext("application"); closeErr != nil {
+		return nil, errors.Wrap(closeErr, "Error closing for application")
+	}
 
 	// Reserved Field (Compartmentalized so the "reserved" variable can't leak)
 	{
@@ -203,8 +209,13 @@ func (m *_StatusRequestBinaryStateDeprecated) Serialize(writeBuffer utils.WriteB
 		}
 
 		// Simple Field (application)
-		application := byte(m.GetApplication())
-		_applicationErr := writeBuffer.WriteByte("application", (application))
+		if pushErr := writeBuffer.PushContext("application"); pushErr != nil {
+			return errors.Wrap(pushErr, "Error pushing for application")
+		}
+		_applicationErr := writeBuffer.WriteSerializable(m.GetApplication())
+		if popErr := writeBuffer.PopContext("application"); popErr != nil {
+			return errors.Wrap(popErr, "Error popping for application")
+		}
 		if _applicationErr != nil {
 			return errors.Wrap(_applicationErr, "Error serializing 'application' field")
 		}
diff --git a/plc4go/protocols/cbus/readwrite/model/StatusRequestLevel.go b/plc4go/protocols/cbus/readwrite/model/StatusRequestLevel.go
index 58f871d70..746f59561 100644
--- a/plc4go/protocols/cbus/readwrite/model/StatusRequestLevel.go
+++ b/plc4go/protocols/cbus/readwrite/model/StatusRequestLevel.go
@@ -33,7 +33,7 @@ type StatusRequestLevel interface {
 	utils.Serializable
 	StatusRequest
 	// GetApplication returns Application (property field)
-	GetApplication() byte
+	GetApplication() ApplicationIdContainer
 	// GetStartingGroupAddressLabel returns StartingGroupAddressLabel (property field)
 	GetStartingGroupAddressLabel() byte
 }
@@ -48,7 +48,7 @@ type StatusRequestLevelExactly interface {
 // _StatusRequestLevel is the data-structure of this message
 type _StatusRequestLevel struct {
 	*_StatusRequest
-	Application               byte
+	Application               ApplicationIdContainer
 	StartingGroupAddressLabel byte
 }
 
@@ -75,7 +75,7 @@ func (m *_StatusRequestLevel) GetParent() StatusRequest {
 /////////////////////// Accessors for property fields.
 ///////////////////////
 
-func (m *_StatusRequestLevel) GetApplication() byte {
+func (m *_StatusRequestLevel) GetApplication() ApplicationIdContainer {
 	return m.Application
 }
 
@@ -89,7 +89,7 @@ func (m *_StatusRequestLevel) GetStartingGroupAddressLabel() byte {
 ///////////////////////////////////////////////////////////
 
 // NewStatusRequestLevel factory function for _StatusRequestLevel
-func NewStatusRequestLevel(application byte, startingGroupAddressLabel byte, statusType byte) *_StatusRequestLevel {
+func NewStatusRequestLevel(application ApplicationIdContainer, startingGroupAddressLabel byte, statusType byte) *_StatusRequestLevel {
 	_result := &_StatusRequestLevel{
 		Application:               application,
 		StartingGroupAddressLabel: startingGroupAddressLabel,
@@ -178,11 +178,17 @@ func StatusRequestLevelParse(readBuffer utils.ReadBuffer) (StatusRequestLevel, e
 	}
 
 	// Simple Field (application)
-	_application, _applicationErr := readBuffer.ReadByte("application")
+	if pullErr := readBuffer.PullContext("application"); pullErr != nil {
+		return nil, errors.Wrap(pullErr, "Error pulling for application")
+	}
+	_application, _applicationErr := ApplicationIdContainerParse(readBuffer)
 	if _applicationErr != nil {
 		return nil, errors.Wrap(_applicationErr, "Error parsing 'application' field of StatusRequestLevel")
 	}
 	application := _application
+	if closeErr := readBuffer.CloseContext("application"); closeErr != nil {
+		return nil, errors.Wrap(closeErr, "Error closing for application")
+	}
 
 	// Simple Field (startingGroupAddressLabel)
 	_startingGroupAddressLabel, _startingGroupAddressLabelErr := readBuffer.ReadByte("startingGroupAddressLabel")
@@ -235,8 +241,13 @@ func (m *_StatusRequestLevel) Serialize(writeBuffer utils.WriteBuffer) error {
 		}
 
 		// Simple Field (application)
-		application := byte(m.GetApplication())
-		_applicationErr := writeBuffer.WriteByte("application", (application))
+		if pushErr := writeBuffer.PushContext("application"); pushErr != nil {
+			return errors.Wrap(pushErr, "Error pushing for application")
+		}
+		_applicationErr := writeBuffer.WriteSerializable(m.GetApplication())
+		if popErr := writeBuffer.PopContext("application"); popErr != nil {
+			return errors.Wrap(popErr, "Error popping for application")
+		}
 		if _applicationErr != nil {
 			return errors.Wrap(_applicationErr, "Error serializing 'application' field")
 		}
diff --git a/plc4go/tests/drivers/tests/manual_cbus_driver_test.go b/plc4go/tests/drivers/tests/manual_cbus_driver_test.go
index d2a1e70da..025bb3599 100644
--- a/plc4go/tests/drivers/tests/manual_cbus_driver_test.go
+++ b/plc4go/tests/drivers/tests/manual_cbus_driver_test.go
@@ -39,6 +39,9 @@ func TestManualCBusDriver(t *testing.T) {
 
 	test.AddTestCase("status/binary/0x04", true)
 	test.AddTestCase("status/level=0x40/0x04", true)
+	test.AddTestCase("cal/recall=[INTERFACE_OPTIONS_1, 1]", true)
+	test.AddTestCase("cal/identify=[FirmwareVersion]", true)
+	test.AddTestCase("cal/gestatus=[0xFF, 1]", true)
 
 	test.Run()
 }
diff --git a/protocols/c-bus/src/main/resources/protocols/cbus/c-bus.mspec b/protocols/c-bus/src/main/resources/protocols/cbus/c-bus.mspec
index 3e8eb4486..518a102f1 100644
--- a/protocols/c-bus/src/main/resources/protocols/cbus/c-bus.mspec
+++ b/protocols/c-bus/src/main/resources/protocols/cbus/c-bus.mspec
@@ -1263,20 +1263,20 @@
     [peek    byte     statusType           ]
     [typeSwitch statusType
         ['0x7A' *BinaryState
-            [reserved   byte      '0x7A'                                              ]
-            [simple     byte      application                                         ]
-            [reserved   byte      '0x00'                                              ]
+            [reserved   byte                    '0x7A'                                              ]
+            [simple     ApplicationIdContainer  application                                         ]
+            [reserved   byte                    '0x00'                                              ]
         ]
         ['0xFA' *BinaryStateDeprecated
-            [reserved   byte      '0xFA'                                              ]
-            [simple     byte      application                                         ]
-            [reserved   byte      '0x00'                                              ]
+            [reserved   byte                    '0xFA'                                              ]
+            [simple     ApplicationIdContainer  application                                         ]
+            [reserved   byte                    '0x00'                                              ]
         ]
         ['0x73' *Level
-            [reserved   byte      '0x73'                                              ]
-            [reserved   byte      '0x07'                                              ]
-            [simple     byte      application                                         ]
-            [simple     byte      startingGroupAddressLabel                           ]
+            [reserved   byte                    '0x73'                                              ]
+            [reserved   byte                    '0x07'                                              ]
+            [simple     ApplicationIdContainer  application                                         ]
+            [simple     byte                    startingGroupAddressLabel                           ]
             [validation           'startingGroupAddressLabel == 0x00
                                 || startingGroupAddressLabel == 0x20
                                 || startingGroupAddressLabel == 0x40
@@ -1604,4 +1604,4 @@
 [type ResponseTermination
     [const      byte    cr  0x0D                                    ] // 0xD == "<cr>"
     [const      byte    lf  0x0A                                    ] // 0xA == "<lf>"
-]
\ No newline at end of file
+]


[plc4x] 01/02: fix(plc4go/s7): fixed serialize of PlcStringField

Posted by sr...@apache.org.
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

commit 01e6c6d0fbc4d59bf66a43f7630afb0044f238c8
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Tue Jul 26 19:28:35 2022 +0200

    fix(plc4go/s7): fixed serialize of PlcStringField
---
 plc4go/internal/s7/Field.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/plc4go/internal/s7/Field.go b/plc4go/internal/s7/Field.go
index f28cd7b89..98c3a48e3 100644
--- a/plc4go/internal/s7/Field.go
+++ b/plc4go/internal/s7/Field.go
@@ -165,7 +165,7 @@ func (m PlcStringField) Serialize(writeBuffer utils.WriteBuffer) error {
 	if err := writeBuffer.WriteUint16("numElements", 16, m.NumElements); err != nil {
 		return err
 	}
-	if err := writeBuffer.WriteUint16("numElements", 16, m.stringLength); err != nil {
+	if err := writeBuffer.WriteUint16("stringLength", 16, m.stringLength); err != nil {
 		return err
 	}
 	if err := writeBuffer.WriteString("dataType", uint32(len(m.Datatype.String())*8), "UTF-8", m.Datatype.String()); err != nil {