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/08/08 10:45:38 UTC

[plc4x] 01/02: feat(plc4go/cbus): added new info field for browse

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 456ba1d50889e7b9c52621caff3a7eb824fa2a40
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Mon Aug 8 12:45:04 2022 +0200

    feat(plc4go/cbus): added new info field for browse
---
 plc4go/internal/cbus/Field.go            | 99 ++++++++++++++++++++++++++++++--
 plc4go/internal/cbus/FieldHandler.go     | 60 ++++++++++++++++++-
 plc4go/internal/cbus/fieldtype_string.go |  5 +-
 3 files changed, 156 insertions(+), 8 deletions(-)

diff --git a/plc4go/internal/cbus/Field.go b/plc4go/internal/cbus/Field.go
index c6bfebdc9..66145fb56 100644
--- a/plc4go/internal/cbus/Field.go
+++ b/plc4go/internal/cbus/Field.go
@@ -33,6 +33,16 @@ const (
 	StatusRequestTypeLevel
 )
 
+func (s StatusRequestType) String() string {
+	switch s {
+	case StatusRequestTypeBinaryState:
+		return "StatusRequestTypeBinaryState"
+	case StatusRequestTypeLevel:
+		return "StatusRequestTypeLevel"
+	}
+	return ""
+}
+
 // StatusField can be used to query status using a P-to-MP-StatusRequest command
 type StatusField interface {
 	model.PlcField
@@ -51,9 +61,14 @@ func NewStatusField(statusRequestType StatusRequestType, startingGroupAddressLab
 	}
 }
 
+type CalField interface {
+	GetUnitAddress() readWriteModel.UnitAddress
+}
+
 // CALRecallField can be used to get device/network management fields
 type CALRecallField interface {
 	model.PlcField
+	CalField
 	GetParameter() readWriteModel.Parameter
 	GetCount() uint8
 }
@@ -71,6 +86,7 @@ func NewCALRecallField(unitAddress readWriteModel.UnitAddress, parameter readWri
 // CALIdentifyField can be used to get device/network management fields
 type CALIdentifyField interface {
 	model.PlcField
+	CalField
 	GetAttribute() readWriteModel.Attribute
 }
 
@@ -86,6 +102,7 @@ func NewCALIdentifyField(unitAddress readWriteModel.UnitAddress, attribute readW
 // CALGetstatusField can be used to get device/network management fields
 type CALGetstatusField interface {
 	model.PlcField
+	CalField
 	GetParameter() readWriteModel.Parameter
 	GetCount() uint8
 }
@@ -119,6 +136,7 @@ func NewSALMonitorField(unitAddress readWriteModel.UnitAddress, application read
 // MMIMonitorField can be used to monitor mmi fields
 type MMIMonitorField interface {
 	model.PlcField
+	CalField
 	GetUnitAddress() readWriteModel.UnitAddress
 	GetApplication() readWriteModel.ApplicationIdContainer
 }
@@ -132,6 +150,22 @@ func NewMMIMonitorField(unitAddress readWriteModel.UnitAddress, application read
 	}
 }
 
+// UnitInfoField can be used to get information about unit(s)
+type UnitInfoField interface {
+	model.PlcField
+	GetUnitAddress() *readWriteModel.UnitAddress
+	GetAttribute() *readWriteModel.Attribute
+}
+
+func NewUnitInfoField(unitAddress *readWriteModel.UnitAddress, attribute *readWriteModel.Attribute, numElements uint16) UnitInfoField {
+	return &unitInfoField{
+		unitAddress: unitAddress,
+		fieldType:   UNIT_INFO,
+		attribute:   attribute,
+		numElements: numElements,
+	}
+}
+
 ///////////////////////////////////////
 ///////////////////////////////////////
 //
@@ -187,6 +221,13 @@ type mmiMonitorField struct {
 	numElements uint16
 }
 
+type unitInfoField struct {
+	fieldType   FieldType
+	unitAddress *readWriteModel.UnitAddress
+	attribute   *readWriteModel.Attribute
+	numElements uint16
+}
+
 //
 // Internal section
 //
@@ -222,8 +263,7 @@ func (m statusField) Serialize(writeBuffer utils.WriteBuffer) error {
 		return err
 	}
 
-	// TODO: add string representation
-	if err := writeBuffer.WriteUint8("statusRequestType", 8, uint8(m.statusRequestType)); err != nil {
+	if err := writeBuffer.WriteUint8("statusRequestType", 8, uint8(m.statusRequestType), utils.WithAdditionalStringRepresentation(m.statusRequestType.String())); err != nil {
 		return err
 	}
 	if m.startingGroupAddressLabel != nil {
@@ -241,6 +281,10 @@ func (m statusField) Serialize(writeBuffer utils.WriteBuffer) error {
 	return nil
 }
 
+func (m calField) GetUnitAddress() readWriteModel.UnitAddress {
+	return m.unitAddress
+}
+
 func (m calField) Serialize(writeBuffer utils.WriteBuffer) error {
 	return m.unitAddress.Serialize(writeBuffer)
 }
@@ -274,9 +318,10 @@ func (m calRecallField) Serialize(writeBuffer utils.WriteBuffer) error {
 		return err
 	}
 
-	if err := writeBuffer.WriteUint8("parameter", 8, uint8(m.parameter), utils.WithAdditionalStringRepresentation(m.parameter.String())); err != nil {
+	if err := m.parameter.Serialize(writeBuffer); err != nil {
 		return err
 	}
+
 	if err := writeBuffer.WriteUint8("count", 8, m.count); err != nil {
 		return err
 	}
@@ -312,7 +357,7 @@ func (c calIdentifyField) Serialize(writeBuffer utils.WriteBuffer) error {
 		return err
 	}
 
-	if err := writeBuffer.WriteUint8("attribute", 8, uint8(c.attribute), utils.WithAdditionalStringRepresentation(c.attribute.String())); err != nil {
+	if err := c.attribute.Serialize(writeBuffer); err != nil {
 		return err
 	}
 
@@ -351,9 +396,10 @@ func (c calGetstatusField) Serialize(writeBuffer utils.WriteBuffer) error {
 		return err
 	}
 
-	if err := writeBuffer.WriteUint8("parameter", 8, uint8(c.parameter), utils.WithAdditionalStringRepresentation(c.parameter.String())); err != nil {
+	if err := c.parameter.Serialize(writeBuffer); err != nil {
 		return err
 	}
+
 	if err := writeBuffer.WriteUint8("count", 8, c.count); err != nil {
 		return err
 	}
@@ -439,3 +485,46 @@ func (m mmiMonitorField) Serialize(writeBuffer utils.WriteBuffer) error {
 	}
 	return nil
 }
+
+func (u unitInfoField) GetUnitAddress() *readWriteModel.UnitAddress {
+	return u.unitAddress
+}
+
+func (u unitInfoField) GetAttribute() *readWriteModel.Attribute {
+	return u.attribute
+}
+
+func (u unitInfoField) GetAddressString() string {
+	return fmt.Sprintf("%d[%d]", u.fieldType, u.numElements)
+}
+
+func (u unitInfoField) GetTypeName() string {
+	return u.fieldType.GetName()
+}
+
+func (u unitInfoField) GetQuantity() uint16 {
+	return u.numElements
+}
+
+func (u unitInfoField) Serialize(writeBuffer utils.WriteBuffer) error {
+	if err := writeBuffer.PushContext(u.fieldType.GetName()); err != nil {
+		return err
+	}
+
+	if unitAddress := u.unitAddress; unitAddress != nil {
+		if err := (*unitAddress).Serialize(writeBuffer); err != nil {
+			return err
+		}
+	}
+
+	if attribute := u.attribute; attribute != nil {
+		if err := (*attribute).Serialize(writeBuffer); err != nil {
+			return err
+		}
+	}
+
+	if err := writeBuffer.PopContext(u.fieldType.GetName()); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/plc4go/internal/cbus/FieldHandler.go b/plc4go/internal/cbus/FieldHandler.go
index ece7035b4..c62cb7a8f 100644
--- a/plc4go/internal/cbus/FieldHandler.go
+++ b/plc4go/internal/cbus/FieldHandler.go
@@ -40,6 +40,7 @@ const (
 	CAL_GETSTATUS
 	SAL_MONITOR
 	MMI_STATUS_MONITOR
+	UNIT_INFO
 )
 
 func (i FieldType) GetName() string {
@@ -51,14 +52,16 @@ type FieldHandler struct {
 	calPattern           *regexp.Regexp
 	salMonitorPattern    *regexp.Regexp
 	mmiMonitorPattern    *regexp.Regexp
+	unityQuery           *regexp.Regexp
 }
 
 func NewFieldHandler() FieldHandler {
 	return FieldHandler{
 		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+)])`),
+		calPattern:           regexp.MustCompile(`^cal/(?P<unitAddress>.*)/(?P<calType>recall=\[(?P<recallParamNo>\w+), ?(?P<recallCount>\d+)]|identify=(?P<identifyAttribute>\w+)|getstatus=(?P<getstatusParamNo>\w+), ?(?P<getstatusCount>\d+))`),
 		salMonitorPattern:    regexp.MustCompile(`^salmonitor/(?P<unitAddress>.*)/(?P<application>.*)`),
 		mmiMonitorPattern:    regexp.MustCompile(`^mmimonitor/(?P<unitAddress>.*)/(?P<application>.*)`),
+		unityQuery:           regexp.MustCompile(`^info/(?P<unitAddress>.*)/(?P<identifyAttribute>\w+)`),
 	}
 }
 
@@ -275,6 +278,61 @@ func (m FieldHandler) ParseQuery(query string) (model.PlcField, error) {
 		}
 
 		return NewMMIMonitorField(unitAddress, application, 1), nil
+	} else if match := utils.GetSubgroupMatches(m.unityQuery, query); match != nil {
+		var unitAddress *readWriteModel.UnitAddress
+		unitAddressArgument := match["unitAddress"]
+		if unitAddressArgument == "*" {
+			unitAddress = nil
+		} else 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")
+			}
+			var unitAddressVar readWriteModel.UnitAddress
+			unitAddressVar = readWriteModel.NewUnitAddress(decodedHex[0])
+			unitAddress = &unitAddressVar
+		} else {
+			atoi, err := strconv.ParseUint(unitAddressArgument, 10, 8)
+			if err != nil {
+				return nil, errors.Errorf("Unknown unit address %s", unitAddressArgument)
+			}
+			var unitAddressVar readWriteModel.UnitAddress
+			unitAddressVar = readWriteModel.NewUnitAddress(byte(atoi))
+			unitAddress = &unitAddressVar
+		}
+
+		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")
+			}
+			var attributeVar readWriteModel.Attribute
+			attributeVar = readWriteModel.Attribute(decodedHex[0])
+			attribute = &attributeVar
+		} else {
+			if atoi, err := strconv.ParseUint(attributeArgument, 10, 8); err == nil {
+				var attributeVar readWriteModel.Attribute
+				attributeVar = readWriteModel.Attribute(atoi)
+				attribute = &attributeVar
+			} else {
+				parameterByName, ok := readWriteModel.AttributeByName(attributeArgument)
+				if !ok {
+					return nil, errors.Errorf("Unknown attributeArgument %s", attributeArgument)
+				}
+				var attributeVar readWriteModel.Attribute
+				attributeVar = parameterByName
+				attribute = &attributeVar
+			}
+		}
+		return NewUnitInfoField(unitAddress, attribute, 1), nil
 	} else {
 		return nil, errors.Errorf("Unable to parse %s", query)
 	}
diff --git a/plc4go/internal/cbus/fieldtype_string.go b/plc4go/internal/cbus/fieldtype_string.go
index dd663f49a..0456cc67d 100644
--- a/plc4go/internal/cbus/fieldtype_string.go
+++ b/plc4go/internal/cbus/fieldtype_string.go
@@ -31,11 +31,12 @@ func _() {
 	_ = x[CAL_GETSTATUS-3]
 	_ = x[SAL_MONITOR-4]
 	_ = x[MMI_STATUS_MONITOR-5]
+	_ = x[UNIT_INFO-6]
 }
 
-const _FieldType_name = "STATUSCAL_RECALLCAL_IDENTIFYCAL_GETSTATUSSAL_MONITORMMI_STATUS_MONITOR"
+const _FieldType_name = "STATUSCAL_RECALLCAL_IDENTIFYCAL_GETSTATUSSAL_MONITORMMI_STATUS_MONITORUNIT_INFO"
 
-var _FieldType_index = [...]uint8{0, 6, 16, 28, 41, 52, 70}
+var _FieldType_index = [...]uint8{0, 6, 16, 28, 41, 52, 70, 79}
 
 func (i FieldType) String() string {
 	if i >= FieldType(len(_FieldType_index)-1) {