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/01/11 19:03:04 UTC

[plc4x] branch develop updated (56d85b3 -> dc9b50e)

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 56d85b3  feat(bacnet): support for more object types
     new e5aef05  refactor(bacnet): re-arrange some value
     new dc9b50e  fix(bacnet): enable tag numbers > 14

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:
 .../resources/templates/go/model-template.go.ftlh  |  15 +-
 .../resources/templates/java/io-template.java.ftlh |   2 +-
 .../templates/java/model-template.java.ftlh        |   7 -
 .../plc4go/bacnetip/readwrite/ParserHelper.go      |   8 +
 .../plc4go/bacnetip/readwrite/XmlParserHelper.go   |  31 ++-
 .../bacnetip/readwrite/model/BACnetAction.go       |   4 +-
 ...firmedServiceRequestConfirmedCOVNotification.go |  10 +-
 .../model/BACnetConstructedDataElement.go          |  37 +--
 .../bacnetip/readwrite/model/BACnetContextTag.go   |  22 +-
 .../readwrite/model/BACnetContextTagEnumerated.go  |  27 +--
 .../model/BACnetNotificationParameters.go          |  30 ++-
 .../BACnetNotificationParametersBufferReady.go     |  11 +-
 ...ACnetNotificationParametersChangeOfBitString.go |  11 +-
 .../BACnetNotificationParametersChangeOfState.go   |  11 +-
 .../BACnetNotificationParametersChangeOfValue.go   |  11 +-
 ...tNotificationParametersChangeOfValueNewValue.go |  30 ++-
 ...onParametersChangeOfValueNewValueChangedBits.go |  11 +-
 ...nParametersChangeOfValueNewValueChangedValue.go |  11 +-
 ...BACnetNotificationParametersComplexEventType.go | 124 ++--------
 .../model/BACnetNotificationParametersExtended.go  |  11 +-
 .../BACnetNotificationParametersUnsignedRange.go   |  11 +-
 .../readwrite/model/BACnetPropertyStates.go        |  30 ++-
 .../readwrite/model/BACnetPropertyStatesAction.go  |  11 +-
 .../readwrite/model/BACnetPropertyStatesBoolean.go |  11 +-
 .../readwrite/model/BACnetPropertyValues.go        | 208 +++++++++++++++++
 ...{BACnetApplicationTag.go => BACnetTagHeader.go} | 155 +++++--------
 .../bacnetip/readwrite/model/BACnetTimeStamp.go    |  30 ++-
 .../readwrite/model/BACnetTimeStampDateTime.go     |  11 +-
 .../readwrite/model/BACnetTimeStampSequence.go     |  11 +-
 .../readwrite/model/BACnetTimeStampTime.go         |  11 +-
 ...rmedServiceRequestUnconfirmedCOVNotification.go |  10 +-
 .../plc4x/java/bacnetip/RandomPackagesTest.java    |  29 ++-
 .../spi/codegen/fields/FieldReaderOptional.java    |   4 +
 .../resources/protocols/bacnetip/bacnetip.mspec    | 251 +++++++++++++--------
 34 files changed, 722 insertions(+), 485 deletions(-)
 create mode 100644 plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyValues.go
 copy plc4go/internal/plc4go/bacnetip/readwrite/model/{BACnetApplicationTag.go => BACnetTagHeader.go} (60%)

[plc4x] 01/02: refactor(bacnet): re-arrange some value

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 e5aef0517b6e5d7985109a7a82e235d2d7f036b7
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Tue Jan 11 18:28:03 2022 +0100

    refactor(bacnet): re-arrange some value
---
 .../plc4go/bacnetip/readwrite/ParserHelper.go      |   6 +
 .../plc4go/bacnetip/readwrite/XmlParserHelper.go   |   7 +
 ...firmedServiceRequestConfirmedCOVNotification.go |  10 +-
 ...BACnetNotificationParametersComplexEventType.go | 115 ++----------
 .../readwrite/model/BACnetPropertyValues.go        | 208 +++++++++++++++++++++
 ...rmedServiceRequestUnconfirmedCOVNotification.go |  10 +-
 .../plc4x/java/bacnetip/RandomPackagesTest.java    |  28 +--
 .../resources/protocols/bacnetip/bacnetip.mspec    | 142 ++++++++------
 8 files changed, 348 insertions(+), 178 deletions(-)

diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/ParserHelper.go b/plc4go/internal/plc4go/bacnetip/readwrite/ParserHelper.go
index b41ba4b..498ce36 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/ParserHelper.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/ParserHelper.go
@@ -129,6 +129,12 @@ func (m BacnetipParserHelper) Parse(typeName string, arguments []string, io util
 		return model.BACnetDeviceObjectPropertyReferenceParse(io, tagNumber)
 	case "BACnetConstructedDataElement":
 		return model.BACnetConstructedDataElementParse(io)
+	case "BACnetPropertyValues":
+		tagNumber, err := utils.StrToUint8(arguments[0])
+		if err != nil {
+			return nil, errors.Wrap(err, "Error parsing")
+		}
+		return model.BACnetPropertyValuesParse(io, tagNumber)
 	case "BACnetPropertyValue":
 		return model.BACnetPropertyValueParse(io)
 	case "BACnetServiceAck":
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/XmlParserHelper.go b/plc4go/internal/plc4go/bacnetip/readwrite/XmlParserHelper.go
index c240497..3f4e0e9 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/XmlParserHelper.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/XmlParserHelper.go
@@ -153,6 +153,13 @@ func (m BacnetipXmlParserHelper) Parse(typeName string, xmlString string, parser
 		return model.BACnetDeviceObjectPropertyReferenceParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)), tagNumber)
 	case "BACnetConstructedDataElement":
 		return model.BACnetConstructedDataElementParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
+	case "BACnetPropertyValues":
+		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 4)
+		if err != nil {
+			return nil, err
+		}
+		tagNumber := uint8(parsedUint0)
+		return model.BACnetPropertyValuesParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)), tagNumber)
 	case "BACnetPropertyValue":
 		return model.BACnetPropertyValueParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
 	case "BACnetServiceAck":
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConfirmedServiceRequestConfirmedCOVNotification.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConfirmedServiceRequestConfirmedCOVNotification.go
index 77b01a9..7dc4764 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConfirmedServiceRequestConfirmedCOVNotification.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConfirmedServiceRequestConfirmedCOVNotification.go
@@ -33,7 +33,7 @@ type BACnetConfirmedServiceRequestConfirmedCOVNotification struct {
 	MonitoredObjectIdentifier   *BACnetContextTagObjectIdentifier
 	IssueConfirmed              *BACnetContextTagBoolean
 	LifetimeInSeconds           *BACnetContextTagUnsignedInteger
-	ListOfValues                *BACnetConstructedData
+	ListOfValues                *BACnetPropertyValues
 }
 
 // The corresponding interface
@@ -53,7 +53,7 @@ func (m *BACnetConfirmedServiceRequestConfirmedCOVNotification) ServiceChoice()
 func (m *BACnetConfirmedServiceRequestConfirmedCOVNotification) InitializeParent(parent *BACnetConfirmedServiceRequest) {
 }
 
-func NewBACnetConfirmedServiceRequestConfirmedCOVNotification(subscriberProcessIdentifier *BACnetContextTagUnsignedInteger, monitoredObjectIdentifier *BACnetContextTagObjectIdentifier, issueConfirmed *BACnetContextTagBoolean, lifetimeInSeconds *BACnetContextTagUnsignedInteger, listOfValues *BACnetConstructedData) *BACnetConfirmedServiceRequest {
+func NewBACnetConfirmedServiceRequestConfirmedCOVNotification(subscriberProcessIdentifier *BACnetContextTagUnsignedInteger, monitoredObjectIdentifier *BACnetContextTagObjectIdentifier, issueConfirmed *BACnetContextTagBoolean, lifetimeInSeconds *BACnetContextTagUnsignedInteger, listOfValues *BACnetPropertyValues) *BACnetConfirmedServiceRequest {
 	child := &BACnetConfirmedServiceRequestConfirmedCOVNotification{
 		SubscriberProcessIdentifier:   subscriberProcessIdentifier,
 		MonitoredObjectIdentifier:     monitoredObjectIdentifier,
@@ -179,11 +179,11 @@ func BACnetConfirmedServiceRequestConfirmedCOVNotificationParse(readBuffer utils
 	if pullErr := readBuffer.PullContext("listOfValues"); pullErr != nil {
 		return nil, pullErr
 	}
-	_listOfValues, _listOfValuesErr := BACnetConstructedDataParse(readBuffer, uint8(4))
+	_listOfValues, _listOfValuesErr := BACnetPropertyValuesParse(readBuffer, uint8(4))
 	if _listOfValuesErr != nil {
 		return nil, errors.Wrap(_listOfValuesErr, "Error parsing 'listOfValues' field")
 	}
-	listOfValues := CastBACnetConstructedData(_listOfValues)
+	listOfValues := CastBACnetPropertyValues(_listOfValues)
 	if closeErr := readBuffer.CloseContext("listOfValues"); closeErr != nil {
 		return nil, closeErr
 	}
@@ -198,7 +198,7 @@ func BACnetConfirmedServiceRequestConfirmedCOVNotificationParse(readBuffer utils
 		MonitoredObjectIdentifier:     CastBACnetContextTagObjectIdentifier(monitoredObjectIdentifier),
 		IssueConfirmed:                CastBACnetContextTagBoolean(issueConfirmed),
 		LifetimeInSeconds:             CastBACnetContextTagUnsignedInteger(lifetimeInSeconds),
-		ListOfValues:                  CastBACnetConstructedData(listOfValues),
+		ListOfValues:                  CastBACnetPropertyValues(listOfValues),
 		BACnetConfirmedServiceRequest: &BACnetConfirmedServiceRequest{},
 	}
 	_child.BACnetConfirmedServiceRequest.Child = _child
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersComplexEventType.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersComplexEventType.go
index 06b42fc..4c971ea 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersComplexEventType.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersComplexEventType.go
@@ -29,9 +29,7 @@ import (
 // The data-structure of this message
 type BACnetNotificationParametersComplexEventType struct {
 	*BACnetNotificationParameters
-	InnerOpeningTag *BACnetOpeningTag
-	Data            []*BACnetPropertyValue
-	InnerClosingTag *BACnetClosingTag
+	ListOfValues *BACnetPropertyValues
 }
 
 // The corresponding interface
@@ -51,11 +49,9 @@ func (m *BACnetNotificationParametersComplexEventType) InitializeParent(parent *
 	m.ClosingTag = closingTag
 }
 
-func NewBACnetNotificationParametersComplexEventType(innerOpeningTag *BACnetOpeningTag, data []*BACnetPropertyValue, innerClosingTag *BACnetClosingTag, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetNotificationParameters {
+func NewBACnetNotificationParametersComplexEventType(listOfValues *BACnetPropertyValues, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetNotificationParameters {
 	child := &BACnetNotificationParametersComplexEventType{
-		InnerOpeningTag:              innerOpeningTag,
-		Data:                         data,
-		InnerClosingTag:              innerClosingTag,
+		ListOfValues:                 listOfValues,
 		BACnetNotificationParameters: NewBACnetNotificationParameters(openingTag, peekedTagNumber, closingTag),
 	}
 	child.Child = child
@@ -92,18 +88,8 @@ func (m *BACnetNotificationParametersComplexEventType) LengthInBits() uint16 {
 func (m *BACnetNotificationParametersComplexEventType) LengthInBitsConditional(lastItem bool) uint16 {
 	lengthInBits := uint16(m.ParentLengthInBits())
 
-	// Simple field (innerOpeningTag)
-	lengthInBits += m.InnerOpeningTag.LengthInBits()
-
-	// Array field
-	if len(m.Data) > 0 {
-		for _, element := range m.Data {
-			lengthInBits += element.LengthInBits()
-		}
-	}
-
-	// Simple field (innerClosingTag)
-	lengthInBits += m.InnerClosingTag.LengthInBits()
+	// Simple field (listOfValues)
+	lengthInBits += m.ListOfValues.LengthInBits()
 
 	return lengthInBits
 }
@@ -117,49 +103,16 @@ func BACnetNotificationParametersComplexEventTypeParse(readBuffer utils.ReadBuff
 		return nil, pullErr
 	}
 
-	// Simple Field (innerOpeningTag)
-	if pullErr := readBuffer.PullContext("innerOpeningTag"); pullErr != nil {
-		return nil, pullErr
-	}
-	_innerOpeningTag, _innerOpeningTagErr := BACnetContextTagParse(readBuffer, peekedTagNumber, BACnetDataType_OPENING_TAG)
-	if _innerOpeningTagErr != nil {
-		return nil, errors.Wrap(_innerOpeningTagErr, "Error parsing 'innerOpeningTag' field")
-	}
-	innerOpeningTag := CastBACnetOpeningTag(_innerOpeningTag)
-	if closeErr := readBuffer.CloseContext("innerOpeningTag"); closeErr != nil {
-		return nil, closeErr
-	}
-
-	// Array field (data)
-	if pullErr := readBuffer.PullContext("data", utils.WithRenderAsList(true)); pullErr != nil {
-		return nil, pullErr
-	}
-	// Terminated array
-	data := make([]*BACnetPropertyValue, 0)
-	{
-		for !bool(IsBACnetConstructedDataClosingTag(readBuffer, peekedTagNumber)) {
-			_item, _err := BACnetPropertyValueParse(readBuffer)
-			if _err != nil {
-				return nil, errors.Wrap(_err, "Error parsing 'data' field")
-			}
-			data = append(data, _item)
-
-		}
-	}
-	if closeErr := readBuffer.CloseContext("data", utils.WithRenderAsList(true)); closeErr != nil {
-		return nil, closeErr
-	}
-
-	// Simple Field (innerClosingTag)
-	if pullErr := readBuffer.PullContext("innerClosingTag"); pullErr != nil {
+	// Simple Field (listOfValues)
+	if pullErr := readBuffer.PullContext("listOfValues"); pullErr != nil {
 		return nil, pullErr
 	}
-	_innerClosingTag, _innerClosingTagErr := BACnetContextTagParse(readBuffer, peekedTagNumber, BACnetDataType_CLOSING_TAG)
-	if _innerClosingTagErr != nil {
-		return nil, errors.Wrap(_innerClosingTagErr, "Error parsing 'innerClosingTag' field")
+	_listOfValues, _listOfValuesErr := BACnetPropertyValuesParse(readBuffer, peekedTagNumber)
+	if _listOfValuesErr != nil {
+		return nil, errors.Wrap(_listOfValuesErr, "Error parsing 'listOfValues' field")
 	}
-	innerClosingTag := CastBACnetClosingTag(_innerClosingTag)
-	if closeErr := readBuffer.CloseContext("innerClosingTag"); closeErr != nil {
+	listOfValues := CastBACnetPropertyValues(_listOfValues)
+	if closeErr := readBuffer.CloseContext("listOfValues"); closeErr != nil {
 		return nil, closeErr
 	}
 
@@ -169,9 +122,7 @@ func BACnetNotificationParametersComplexEventTypeParse(readBuffer utils.ReadBuff
 
 	// Create a partially initialized instance
 	_child := &BACnetNotificationParametersComplexEventType{
-		InnerOpeningTag:              CastBACnetOpeningTag(innerOpeningTag),
-		Data:                         data,
-		InnerClosingTag:              CastBACnetClosingTag(innerClosingTag),
+		ListOfValues:                 CastBACnetPropertyValues(listOfValues),
 		BACnetNotificationParameters: &BACnetNotificationParameters{},
 	}
 	_child.BACnetNotificationParameters.Child = _child
@@ -184,44 +135,16 @@ func (m *BACnetNotificationParametersComplexEventType) Serialize(writeBuffer uti
 			return pushErr
 		}
 
-		// Simple Field (innerOpeningTag)
-		if pushErr := writeBuffer.PushContext("innerOpeningTag"); pushErr != nil {
-			return pushErr
-		}
-		_innerOpeningTagErr := m.InnerOpeningTag.Serialize(writeBuffer)
-		if popErr := writeBuffer.PopContext("innerOpeningTag"); popErr != nil {
-			return popErr
-		}
-		if _innerOpeningTagErr != nil {
-			return errors.Wrap(_innerOpeningTagErr, "Error serializing 'innerOpeningTag' field")
-		}
-
-		// Array Field (data)
-		if m.Data != nil {
-			if pushErr := writeBuffer.PushContext("data", utils.WithRenderAsList(true)); pushErr != nil {
-				return pushErr
-			}
-			for _, _element := range m.Data {
-				_elementErr := _element.Serialize(writeBuffer)
-				if _elementErr != nil {
-					return errors.Wrap(_elementErr, "Error serializing 'data' field")
-				}
-			}
-			if popErr := writeBuffer.PopContext("data", utils.WithRenderAsList(true)); popErr != nil {
-				return popErr
-			}
-		}
-
-		// Simple Field (innerClosingTag)
-		if pushErr := writeBuffer.PushContext("innerClosingTag"); pushErr != nil {
+		// Simple Field (listOfValues)
+		if pushErr := writeBuffer.PushContext("listOfValues"); pushErr != nil {
 			return pushErr
 		}
-		_innerClosingTagErr := m.InnerClosingTag.Serialize(writeBuffer)
-		if popErr := writeBuffer.PopContext("innerClosingTag"); popErr != nil {
+		_listOfValuesErr := m.ListOfValues.Serialize(writeBuffer)
+		if popErr := writeBuffer.PopContext("listOfValues"); popErr != nil {
 			return popErr
 		}
-		if _innerClosingTagErr != nil {
-			return errors.Wrap(_innerClosingTagErr, "Error serializing 'innerClosingTag' field")
+		if _listOfValuesErr != nil {
+			return errors.Wrap(_listOfValuesErr, "Error serializing 'listOfValues' field")
 		}
 
 		if popErr := writeBuffer.PopContext("BACnetNotificationParametersComplexEventType"); popErr != nil {
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyValues.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyValues.go
new file mode 100644
index 0000000..c777776
--- /dev/null
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyValues.go
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package model
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils"
+	"github.com/pkg/errors"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// The data-structure of this message
+type BACnetPropertyValues struct {
+	InnerOpeningTag *BACnetOpeningTag
+	Data            []*BACnetPropertyValue
+	InnerClosingTag *BACnetClosingTag
+}
+
+// The corresponding interface
+type IBACnetPropertyValues interface {
+	LengthInBytes() uint16
+	LengthInBits() uint16
+	Serialize(writeBuffer utils.WriteBuffer) error
+}
+
+func NewBACnetPropertyValues(innerOpeningTag *BACnetOpeningTag, data []*BACnetPropertyValue, innerClosingTag *BACnetClosingTag) *BACnetPropertyValues {
+	return &BACnetPropertyValues{InnerOpeningTag: innerOpeningTag, Data: data, InnerClosingTag: innerClosingTag}
+}
+
+func CastBACnetPropertyValues(structType interface{}) *BACnetPropertyValues {
+	castFunc := func(typ interface{}) *BACnetPropertyValues {
+		if casted, ok := typ.(BACnetPropertyValues); ok {
+			return &casted
+		}
+		if casted, ok := typ.(*BACnetPropertyValues); ok {
+			return casted
+		}
+		return nil
+	}
+	return castFunc(structType)
+}
+
+func (m *BACnetPropertyValues) GetTypeName() string {
+	return "BACnetPropertyValues"
+}
+
+func (m *BACnetPropertyValues) LengthInBits() uint16 {
+	return m.LengthInBitsConditional(false)
+}
+
+func (m *BACnetPropertyValues) LengthInBitsConditional(lastItem bool) uint16 {
+	lengthInBits := uint16(0)
+
+	// Simple field (innerOpeningTag)
+	lengthInBits += m.InnerOpeningTag.LengthInBits()
+
+	// Array field
+	if len(m.Data) > 0 {
+		for _, element := range m.Data {
+			lengthInBits += element.LengthInBits()
+		}
+	}
+
+	// Simple field (innerClosingTag)
+	lengthInBits += m.InnerClosingTag.LengthInBits()
+
+	return lengthInBits
+}
+
+func (m *BACnetPropertyValues) LengthInBytes() uint16 {
+	return m.LengthInBits() / 8
+}
+
+func BACnetPropertyValuesParse(readBuffer utils.ReadBuffer, tagNumber uint8) (*BACnetPropertyValues, error) {
+	if pullErr := readBuffer.PullContext("BACnetPropertyValues"); pullErr != nil {
+		return nil, pullErr
+	}
+
+	// Simple Field (innerOpeningTag)
+	if pullErr := readBuffer.PullContext("innerOpeningTag"); pullErr != nil {
+		return nil, pullErr
+	}
+	_innerOpeningTag, _innerOpeningTagErr := BACnetContextTagParse(readBuffer, tagNumber, BACnetDataType_OPENING_TAG)
+	if _innerOpeningTagErr != nil {
+		return nil, errors.Wrap(_innerOpeningTagErr, "Error parsing 'innerOpeningTag' field")
+	}
+	innerOpeningTag := CastBACnetOpeningTag(_innerOpeningTag)
+	if closeErr := readBuffer.CloseContext("innerOpeningTag"); closeErr != nil {
+		return nil, closeErr
+	}
+
+	// Array field (data)
+	if pullErr := readBuffer.PullContext("data", utils.WithRenderAsList(true)); pullErr != nil {
+		return nil, pullErr
+	}
+	// Terminated array
+	data := make([]*BACnetPropertyValue, 0)
+	{
+		for !bool(IsBACnetConstructedDataClosingTag(readBuffer, tagNumber)) {
+			_item, _err := BACnetPropertyValueParse(readBuffer)
+			if _err != nil {
+				return nil, errors.Wrap(_err, "Error parsing 'data' field")
+			}
+			data = append(data, _item)
+
+		}
+	}
+	if closeErr := readBuffer.CloseContext("data", utils.WithRenderAsList(true)); closeErr != nil {
+		return nil, closeErr
+	}
+
+	// Simple Field (innerClosingTag)
+	if pullErr := readBuffer.PullContext("innerClosingTag"); pullErr != nil {
+		return nil, pullErr
+	}
+	_innerClosingTag, _innerClosingTagErr := BACnetContextTagParse(readBuffer, tagNumber, BACnetDataType_CLOSING_TAG)
+	if _innerClosingTagErr != nil {
+		return nil, errors.Wrap(_innerClosingTagErr, "Error parsing 'innerClosingTag' field")
+	}
+	innerClosingTag := CastBACnetClosingTag(_innerClosingTag)
+	if closeErr := readBuffer.CloseContext("innerClosingTag"); closeErr != nil {
+		return nil, closeErr
+	}
+
+	if closeErr := readBuffer.CloseContext("BACnetPropertyValues"); closeErr != nil {
+		return nil, closeErr
+	}
+
+	// Create the instance
+	return NewBACnetPropertyValues(innerOpeningTag, data, innerClosingTag), nil
+}
+
+func (m *BACnetPropertyValues) Serialize(writeBuffer utils.WriteBuffer) error {
+	if pushErr := writeBuffer.PushContext("BACnetPropertyValues"); pushErr != nil {
+		return pushErr
+	}
+
+	// Simple Field (innerOpeningTag)
+	if pushErr := writeBuffer.PushContext("innerOpeningTag"); pushErr != nil {
+		return pushErr
+	}
+	_innerOpeningTagErr := m.InnerOpeningTag.Serialize(writeBuffer)
+	if popErr := writeBuffer.PopContext("innerOpeningTag"); popErr != nil {
+		return popErr
+	}
+	if _innerOpeningTagErr != nil {
+		return errors.Wrap(_innerOpeningTagErr, "Error serializing 'innerOpeningTag' field")
+	}
+
+	// Array Field (data)
+	if m.Data != nil {
+		if pushErr := writeBuffer.PushContext("data", utils.WithRenderAsList(true)); pushErr != nil {
+			return pushErr
+		}
+		for _, _element := range m.Data {
+			_elementErr := _element.Serialize(writeBuffer)
+			if _elementErr != nil {
+				return errors.Wrap(_elementErr, "Error serializing 'data' field")
+			}
+		}
+		if popErr := writeBuffer.PopContext("data", utils.WithRenderAsList(true)); popErr != nil {
+			return popErr
+		}
+	}
+
+	// Simple Field (innerClosingTag)
+	if pushErr := writeBuffer.PushContext("innerClosingTag"); pushErr != nil {
+		return pushErr
+	}
+	_innerClosingTagErr := m.InnerClosingTag.Serialize(writeBuffer)
+	if popErr := writeBuffer.PopContext("innerClosingTag"); popErr != nil {
+		return popErr
+	}
+	if _innerClosingTagErr != nil {
+		return errors.Wrap(_innerClosingTagErr, "Error serializing 'innerClosingTag' field")
+	}
+
+	if popErr := writeBuffer.PopContext("BACnetPropertyValues"); popErr != nil {
+		return popErr
+	}
+	return nil
+}
+
+func (m *BACnetPropertyValues) String() string {
+	if m == nil {
+		return "<nil>"
+	}
+	buffer := utils.NewBoxedWriteBufferWithOptions(true, true)
+	m.Serialize(buffer)
+	return buffer.GetBox().String()
+}
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetUnconfirmedServiceRequestUnconfirmedCOVNotification.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetUnconfirmedServiceRequestUnconfirmedCOVNotification.go
index 8d2638c..698ee80 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetUnconfirmedServiceRequestUnconfirmedCOVNotification.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetUnconfirmedServiceRequestUnconfirmedCOVNotification.go
@@ -33,7 +33,7 @@ type BACnetUnconfirmedServiceRequestUnconfirmedCOVNotification struct {
 	MonitoredDeviceIdentifier   *BACnetContextTagObjectIdentifier
 	MonitoredObjectIdentifier   *BACnetContextTagObjectIdentifier
 	LifetimeInSeconds           *BACnetContextTagUnsignedInteger
-	ListOfValues                *BACnetConstructedData
+	ListOfValues                *BACnetPropertyValues
 }
 
 // The corresponding interface
@@ -53,7 +53,7 @@ func (m *BACnetUnconfirmedServiceRequestUnconfirmedCOVNotification) ServiceChoic
 func (m *BACnetUnconfirmedServiceRequestUnconfirmedCOVNotification) InitializeParent(parent *BACnetUnconfirmedServiceRequest) {
 }
 
-func NewBACnetUnconfirmedServiceRequestUnconfirmedCOVNotification(subscriberProcessIdentifier *BACnetContextTagUnsignedInteger, monitoredDeviceIdentifier *BACnetContextTagObjectIdentifier, monitoredObjectIdentifier *BACnetContextTagObjectIdentifier, lifetimeInSeconds *BACnetContextTagUnsignedInteger, listOfValues *BACnetConstructedData) *BACnetUnconfirmedServiceRequest {
+func NewBACnetUnconfirmedServiceRequestUnconfirmedCOVNotification(subscriberProcessIdentifier *BACnetContextTagUnsignedInteger, monitoredDeviceIdentifier *BACnetContextTagObjectIdentifier, monitoredObjectIdentifier *BACnetContextTagObjectIdentifier, lifetimeInSeconds *BACnetContextTagUnsignedInteger, listOfValues *BACnetPropertyValues) *BACnetUnconfirmedServiceRequest {
 	child := &BACnetUnconfirmedServiceRequestUnconfirmedCOVNotification{
 		SubscriberProcessIdentifier:     subscriberProcessIdentifier,
 		MonitoredDeviceIdentifier:       monitoredDeviceIdentifier,
@@ -179,11 +179,11 @@ func BACnetUnconfirmedServiceRequestUnconfirmedCOVNotificationParse(readBuffer u
 	if pullErr := readBuffer.PullContext("listOfValues"); pullErr != nil {
 		return nil, pullErr
 	}
-	_listOfValues, _listOfValuesErr := BACnetConstructedDataParse(readBuffer, uint8(4))
+	_listOfValues, _listOfValuesErr := BACnetPropertyValuesParse(readBuffer, uint8(4))
 	if _listOfValuesErr != nil {
 		return nil, errors.Wrap(_listOfValuesErr, "Error parsing 'listOfValues' field")
 	}
-	listOfValues := CastBACnetConstructedData(_listOfValues)
+	listOfValues := CastBACnetPropertyValues(_listOfValues)
 	if closeErr := readBuffer.CloseContext("listOfValues"); closeErr != nil {
 		return nil, closeErr
 	}
@@ -198,7 +198,7 @@ func BACnetUnconfirmedServiceRequestUnconfirmedCOVNotificationParse(readBuffer u
 		MonitoredDeviceIdentifier:       CastBACnetContextTagObjectIdentifier(monitoredDeviceIdentifier),
 		MonitoredObjectIdentifier:       CastBACnetContextTagObjectIdentifier(monitoredObjectIdentifier),
 		LifetimeInSeconds:               CastBACnetContextTagUnsignedInteger(lifetimeInSeconds),
-		ListOfValues:                    CastBACnetConstructedData(listOfValues),
+		ListOfValues:                    CastBACnetPropertyValues(listOfValues),
 		BACnetUnconfirmedServiceRequest: &BACnetUnconfirmedServiceRequest{},
 	}
 	_child.BACnetUnconfirmedServiceRequest.Child = _child
diff --git a/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/RandomPackagesTest.java b/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/RandomPackagesTest.java
index 1ce0516..37b9734 100644
--- a/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/RandomPackagesTest.java
+++ b/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/RandomPackagesTest.java
@@ -975,19 +975,19 @@ public class RandomPackagesTest {
                     assertEquals(0, baCnetUnconfirmedServiceRequestUnconfirmedCOVNotification.getMonitoredObjectIdentifier().getInstanceNumber());
                     assertEquals(9, baCnetUnconfirmedServiceRequestUnconfirmedCOVNotification.getLifetimeInSeconds().getActualValue() / 60);
                     {
-                        BACnetContextTagPropertyIdentifier baCnetContextTagPropertyIdentifier = (BACnetContextTagPropertyIdentifier) baCnetUnconfirmedServiceRequestUnconfirmedCOVNotification.getListOfValues().getData().get(0).getContextTag();
+                        BACnetContextTagPropertyIdentifier baCnetContextTagPropertyIdentifier = baCnetUnconfirmedServiceRequestUnconfirmedCOVNotification.getListOfValues().getData().get(0).getPropertyIdentifier();
                         assertEquals(BACnetPropertyIdentifier.PRESENT_VALUE, baCnetContextTagPropertyIdentifier.getValue());
                     }
                     {
-                        BACnetApplicationTagEnumerated baCnetApplicationTagEnumerated = (BACnetApplicationTagEnumerated) baCnetUnconfirmedServiceRequestUnconfirmedCOVNotification.getListOfValues().getData().get(1).getConstructedData().getData().get(0).getApplicationTag();
+                        BACnetApplicationTagEnumerated baCnetApplicationTagEnumerated = (BACnetApplicationTagEnumerated) baCnetUnconfirmedServiceRequestUnconfirmedCOVNotification.getListOfValues().getData().get(0).getPropertyValue().getConstructedData().getData().get(0).getApplicationTag();
                         assertEquals(List.of((byte) 0x0), baCnetApplicationTagEnumerated.getData());
                     }
                     {
-                        BACnetContextTagPropertyIdentifier baCnetContextTagPropertyIdentifier = (BACnetContextTagPropertyIdentifier) baCnetUnconfirmedServiceRequestUnconfirmedCOVNotification.getListOfValues().getData().get(2).getContextTag();
+                        BACnetContextTagPropertyIdentifier baCnetContextTagPropertyIdentifier = baCnetUnconfirmedServiceRequestUnconfirmedCOVNotification.getListOfValues().getData().get(1).getPropertyIdentifier();
                         assertEquals(BACnetPropertyIdentifier.STATUS_FLAGS, baCnetContextTagPropertyIdentifier.getValue());
                     }
                     {
-                        BACnetApplicationTagBitString baCnetApplicationTagBitString = (BACnetApplicationTagBitString) baCnetUnconfirmedServiceRequestUnconfirmedCOVNotification.getListOfValues().getData().get(3).getConstructedData().getData().get(0).getApplicationTag();
+                        BACnetApplicationTagBitString baCnetApplicationTagBitString = (BACnetApplicationTagBitString) baCnetUnconfirmedServiceRequestUnconfirmedCOVNotification.getListOfValues().getData().get(1).getPropertyValue().getConstructedData().getData().get(0).getApplicationTag();
                         assertEquals(Arrays.asList(false, false, false, false), baCnetApplicationTagBitString.getData());
                     }
                 }),
@@ -1223,67 +1223,67 @@ public class RandomPackagesTest {
                     {
                         BACnetNotificationParametersComplexEventType baCnetNotificationParametersComplexEventType = (BACnetNotificationParametersComplexEventType) baCnetConfirmedServiceRequestConfirmedEventNotification.getEventValues();
                         {
-                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getData().get(0);
+                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getListOfValues().getData().get(0);
                             assertEquals(BACnetPropertyIdentifier.VENDOR_PROPRIETARY_VALUE, baCnetPropertyValue.getPropertyIdentifier().getValue());
                             assertEquals(2200, baCnetPropertyValue.getPropertyIdentifier().getProprietaryValue());
                             BACnetApplicationTagCharacterString baCnetApplicationTagCharacterString = (BACnetApplicationTagCharacterString) baCnetPropertyValue.getPropertyValue().getConstructedData().getData().get(0).getApplicationTag();
                             assertEquals("StockingNAE", baCnetApplicationTagCharacterString.getValue());
                         }
                         {
-                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getData().get(1);
+                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getListOfValues().getData().get(1);
                             assertEquals(BACnetPropertyIdentifier.OBJECT_NAME, baCnetPropertyValue.getPropertyIdentifier().getValue());
                             BACnetApplicationTagCharacterString baCnetApplicationTagCharacterString = (BACnetApplicationTagCharacterString) baCnetPropertyValue.getPropertyValue().getConstructedData().getData().get(0).getApplicationTag();
                             assertEquals("StockingNAE/N2-1.NAE4-N2A-DX1.OA-T", baCnetApplicationTagCharacterString.getValue());
                         }
                         {
-                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getData().get(2);
+                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getListOfValues().getData().get(2);
                             assertEquals(BACnetPropertyIdentifier.VENDOR_PROPRIETARY_VALUE, baCnetPropertyValue.getPropertyIdentifier().getValue());
                             assertEquals(2201, baCnetPropertyValue.getPropertyIdentifier().getProprietaryValue());
                             BACnetApplicationTagEnumerated baCnetApplicationTagEnumerated = (BACnetApplicationTagEnumerated) baCnetPropertyValue.getPropertyValue().getConstructedData().getData().get(0).getApplicationTag();
                             assertEquals(List.of((byte) 85), baCnetApplicationTagEnumerated.getData());
                         }
                         {
-                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getData().get(3);
+                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getListOfValues().getData().get(3);
                             assertEquals(BACnetPropertyIdentifier.VENDOR_PROPRIETARY_VALUE, baCnetPropertyValue.getPropertyIdentifier().getValue());
                             assertEquals(2202, baCnetPropertyValue.getPropertyIdentifier().getProprietaryValue());
                             BACnetApplicationTagReal baCnetApplicationTagReal = (BACnetApplicationTagReal) baCnetPropertyValue.getPropertyValue().getConstructedData().getData().get(0).getApplicationTag();
                             assertEquals(35.093750, baCnetApplicationTagReal.getValue());
                         }
                         {
-                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getData().get(4);
+                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getListOfValues().getData().get(4);
                             assertEquals(BACnetPropertyIdentifier.RELIABILITY, baCnetPropertyValue.getPropertyIdentifier().getValue());
                             BACnetApplicationTagEnumerated baCnetApplicationTagEnumerated = (BACnetApplicationTagEnumerated) baCnetPropertyValue.getPropertyValue().getConstructedData().getData().get(0).getApplicationTag();
                             assertEquals(List.of((byte) 0), baCnetApplicationTagEnumerated.getData());
                         }
                         {
-                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getData().get(5);
+                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getListOfValues().getData().get(5);
                             assertEquals(BACnetPropertyIdentifier.VENDOR_PROPRIETARY_VALUE, baCnetPropertyValue.getPropertyIdentifier().getValue());
                             assertEquals(661, baCnetPropertyValue.getPropertyIdentifier().getProprietaryValue());
                             BACnetApplicationTagEnumerated baCnetApplicationTagEnumerated = (BACnetApplicationTagEnumerated) baCnetPropertyValue.getPropertyValue().getConstructedData().getData().get(0).getApplicationTag();
                             assertEquals(List.of((byte) 5), baCnetApplicationTagEnumerated.getData());
                         }
                         {
-                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getData().get(6);
+                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getListOfValues().getData().get(6);
                             assertEquals(BACnetPropertyIdentifier.UNITS, baCnetPropertyValue.getPropertyIdentifier().getValue());
                             BACnetApplicationTagEnumerated baCnetApplicationTagEnumerated = (BACnetApplicationTagEnumerated) baCnetPropertyValue.getPropertyValue().getConstructedData().getData().get(0).getApplicationTag();
                             assertEquals(List.of((byte) 64), baCnetApplicationTagEnumerated.getData());
                         }
                         {
-                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getData().get(7);
+                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getListOfValues().getData().get(7);
                             assertEquals(BACnetPropertyIdentifier.VENDOR_PROPRIETARY_VALUE, baCnetPropertyValue.getPropertyIdentifier().getValue());
                             assertEquals(1659, baCnetPropertyValue.getPropertyIdentifier().getProprietaryValue());
                             BACnetApplicationTagEnumerated baCnetApplicationTagEnumerated = (BACnetApplicationTagEnumerated) baCnetPropertyValue.getPropertyValue().getConstructedData().getData().get(0).getApplicationTag();
                             assertEquals(List.of((byte) 0), baCnetApplicationTagEnumerated.getData());
                         }
                         {
-                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getData().get(8);
+                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getListOfValues().getData().get(8);
                             assertEquals(BACnetPropertyIdentifier.VENDOR_PROPRIETARY_VALUE, baCnetPropertyValue.getPropertyIdentifier().getValue());
                             assertEquals(2203, baCnetPropertyValue.getPropertyIdentifier().getProprietaryValue());
                             BACnetApplicationTagEnumerated baCnetApplicationTagEnumerated = (BACnetApplicationTagEnumerated) baCnetPropertyValue.getPropertyValue().getConstructedData().getData().get(0).getApplicationTag();
                             assertEquals(List.of((byte) 0), baCnetApplicationTagEnumerated.getData());
                         }
                         {
-                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getData().get(9);
+                            BACnetPropertyValue baCnetPropertyValue = baCnetNotificationParametersComplexEventType.getListOfValues().getData().get(9);
                             assertEquals(BACnetPropertyIdentifier.VENDOR_IDENTIFIER, baCnetPropertyValue.getPropertyIdentifier().getValue());
                             BACnetApplicationTagUnsignedInteger baCnetApplicationTagUnsignedInteger = (BACnetApplicationTagUnsignedInteger) baCnetPropertyValue.getPropertyValue().getConstructedData().getData().get(0).getApplicationTag();
                             assertEquals(5, baCnetApplicationTagUnsignedInteger.getActualValue());
diff --git a/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec b/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
index 37ed63d..1712a48 100644
--- a/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
+++ b/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
@@ -18,12 +18,14 @@
  */
 
 [discriminatedType BVLC byteOrder='BIG_ENDIAN'
-    [const         uint 8  bacnetType   0x81       ]
-    [discriminator uint 8  bvlcFunction              ]
-    [implicit      uint 16 bvlcLength 'lengthInBytes']
+    [const         uint 8   bacnetType   0x81         ]
+    [discriminator uint 8   bvlcFunction              ]
+    [implicit      uint 16  bvlcLength 'lengthInBytes']
     [typeSwitch bvlcFunction
         ['0x00' BVLCResult
-            [simple BVLCResultCode code]
+            [simple BVLCResultCode
+                            code
+            ]
         ]
         ['0x01' BVLCWideBroadcastDistributionTable
         ]
@@ -34,7 +36,9 @@
         ['0x04' BVLCForwardedNPDU(uint 16 bvlcLength)
             [array  uint 8  ip    count '4'         ]
             [simple uint 16 port                    ]
-            [simple NPDU('bvlcLength - 10') npdu   ]
+            [simple NPDU('bvlcLength - 10')
+                            npdu
+            ]
         ]
         ['0x05' BVLCRegisterForeignDevice
             [simple uint 16 ttl]
@@ -46,13 +50,19 @@
         ['0x08' BVLCDeleteForeignDeviceTableEntry
         ]
         ['0x09' BVLCDistributeBroadcastToNetwork(uint 16 bvlcLength)
-            [simple NPDU('bvlcLength - 4') npdu]
+            [simple NPDU('bvlcLength - 4')
+                            npdu
+            ]
         ]
         ['0x0A' BVLCOriginalUnicastNPDU(uint 16 bvlcLength)
-            [simple NPDU('bvlcLength - 4') npdu]
+            [simple NPDU('bvlcLength - 4')
+                            npdu
+            ]
         ]
         ['0x0B' BVLCOriginalBroadcastNPDU(uint 16 bvlcLength)
-            [simple NPDU('bvlcLength - 4') npdu]
+            [simple NPDU('bvlcLength - 4')
+                            npdu
+            ]
         ]
         ['0x0C' BVLCSecureBVLL
         ]
@@ -75,8 +85,12 @@
     [optional uint 8        sourceLength              'sourceSpecified']
     [array    uint 8        sourceAddress count       'sourceSpecified ? sourceLength : 0']
     [optional uint 8        hopCount                  'destinationSpecified']
-    [optional NLM('npduLength - (2 + (sourceSpecified ? 3 + sourceLength : 0) + (destinationSpecified ? 3 + destinationLength: 0) + ((destinationSpecified || sourceSpecified) ? 1 : 0))')           nlm                       'messageTypeFieldPresent'  ]
-    [optional APDU('npduLength - (2 + (sourceSpecified ? 3 + sourceLength : 0) + (destinationSpecified ? 3 + destinationLength: 0) + ((destinationSpecified || sourceSpecified) ? 1 : 0))')          apdu                      '!messageTypeFieldPresent' ]
+    [optional NLM('npduLength - (2 + (sourceSpecified ? 3 + sourceLength : 0) + (destinationSpecified ? 3 + destinationLength: 0) + ((destinationSpecified || sourceSpecified) ? 1 : 0))')
+                            nlm                       'messageTypeFieldPresent'
+    ]
+    [optional APDU('npduLength - (2 + (sourceSpecified ? 3 + sourceLength : 0) + (destinationSpecified ? 3 + destinationLength: 0) + ((destinationSpecified || sourceSpecified) ? 1 : 0))')
+                            apdu                      '!messageTypeFieldPresent'
+    ]
 ]
 
 [discriminatedType NLM(uint 16 apduLength)
@@ -96,58 +110,64 @@
     [discriminator uint 4 apduType]
     [typeSwitch apduType
         ['0x0' APDUConfirmedRequest
-            [simple   bit    segmentedMessage                       ]
-            [simple   bit    moreFollows                            ]
-            [simple   bit    segmentedResponseAccepted              ]
-            [reserved uint 2 '0'                                      ]
-            [simple   uint 3 maxSegmentsAccepted                    ]
-            [simple   uint 4 maxApduLengthAccepted                  ]
-            [simple   uint 8 invokeId                               ]
-            [optional uint 8 sequenceNumber       'segmentedMessage']
-            [optional uint 8 proposedWindowSize   'segmentedMessage']
+            [simple   bit       segmentedMessage                       ]
+            [simple   bit       moreFollows                            ]
+            [simple   bit       segmentedResponseAccepted              ]
+            [reserved uint 2    '0'                                    ]
+            [simple   uint 3    maxSegmentsAccepted                    ]
+            [simple   uint 4    maxApduLengthAccepted                  ]
+            [simple   uint 8    invokeId                               ]
+            [optional uint 8    sequenceNumber       'segmentedMessage']
+            [optional uint 8    proposedWindowSize   'segmentedMessage']
             [simple   BACnetConfirmedServiceRequest('apduLength - (3 + (segmentedMessage ? 2 : 0))') serviceRequest]
         ]
         ['0x1' APDUUnconfirmedRequest
             [reserved uint 4                          '0'             ]
-            [simple   BACnetUnconfirmedServiceRequest('apduLength - 1') serviceRequest]
+            [simple   BACnetUnconfirmedServiceRequest('apduLength - 1')
+                                serviceRequest
+            ]
         ]
         ['0x2' APDUSimpleAck
-            [reserved uint 4 '0'               ]
-            [simple   uint 8 originalInvokeId]
-            [simple   uint 8 serviceChoice   ]
+            [reserved uint 4    '0'               ]
+            [simple   uint 8    originalInvokeId]
+            [simple   uint 8    serviceChoice   ]
         ]
         ['0x3' APDUComplexAck
-            [simple   bit               segmentedMessage                     ]
-            [simple   bit               moreFollows                          ]
-            [reserved uint 2            '0'                                    ]
-            [simple   uint 8            originalInvokeId                     ]
-            [optional uint 8            sequenceNumber     'segmentedMessage']
-            [optional uint 8            proposedWindowSize 'segmentedMessage']
-            [simple   BACnetServiceAck  serviceAck                           ]
+            [simple   bit       segmentedMessage                     ]
+            [simple   bit       moreFollows                          ]
+            [reserved uint 2    '0'                                  ]
+            [simple   uint 8    originalInvokeId                     ]
+            [optional uint 8    sequenceNumber     'segmentedMessage']
+            [optional uint 8    proposedWindowSize 'segmentedMessage']
+            [simple   BACnetServiceAck
+                                serviceAck
+            ]
         ]
         ['0x4' APDUSegmentAck
-            [reserved uint 2 '0x00'              ]
-            [simple   bit    negativeAck       ]
-            [simple   bit    server            ]
-            [simple   uint 8 originalInvokeId  ]
-            [simple   uint 8 sequenceNumber    ]
-            [simple   uint 8 proposedWindowSize]
+            [reserved uint 2    '0x00'              ]
+            [simple   bit       negativeAck         ]
+            [simple   bit       server              ]
+            [simple   uint 8    originalInvokeId    ]
+            [simple   uint 8    sequenceNumber      ]
+            [simple   uint 8    proposedWindowSize  ]
         ]
         ['0x5' APDUError
-            [reserved uint 4      '0x00'            ]
-            [simple   uint 8      originalInvokeId]
-            [simple   BACnetError error           ]
+            [reserved uint 4    '0x00'              ]
+            [simple   uint 8    originalInvokeId]
+            [simple   BACnetError
+                                error
+            ]
         ]
         ['0x6' APDUReject
-            [reserved uint 4 '0x00'            ]
-            [simple   uint 8 originalInvokeId]
-            [simple   uint 8 rejectReason    ]
+            [reserved uint 4    '0x00'              ]
+            [simple   uint 8    originalInvokeId    ]
+            [simple   uint 8    rejectReason        ]
         ]
         ['0x7' APDUAbort
-            [reserved uint 3 '0x00'            ]
-            [simple   bit    server          ]
-            [simple   uint 8 originalInvokeId]
-            [simple   uint 8 abortReason     ]
+            [reserved uint 3 '0x00'                 ]
+            [simple   bit    server                 ]
+            [simple   uint 8 originalInvokeId       ]
+            [simple   uint 8 abortReason            ]
         ]
     ]
 ]
@@ -162,7 +182,7 @@
             [simple   BACnetContextTagObjectIdentifier('1', 'BACnetDataType.BACNET_OBJECT_IDENTIFIER') monitoredObjectIdentifier   ]
             [simple   BACnetContextTagBoolean('2', 'BACnetDataType.BOOLEAN')                           issueConfirmed              ]
             [simple   BACnetContextTagUnsignedInteger('3', 'BACnetDataType.UNSIGNED_INTEGER')          lifetimeInSeconds           ]
-            [simple   BACnetConstructedData('4')                                                       listOfValues                ]
+            [simple   BACnetPropertyValues('4')                                                        listOfValues                ]
         ]
         ['0x02' BACnetConfirmedServiceRequestConfirmedEventNotification // Spec complete
             [simple   BACnetContextTagUnsignedInteger('0', 'BACnetDataType.UNSIGNED_INTEGER')          processIdentifier            ]
@@ -285,7 +305,7 @@
             [simple BACnetContextTagObjectIdentifier('1', 'BACnetDataType.BACNET_OBJECT_IDENTIFIER') monitoredDeviceIdentifier   ]
             [simple BACnetContextTagObjectIdentifier('2', 'BACnetDataType.BACNET_OBJECT_IDENTIFIER') monitoredObjectIdentifier   ]
             [simple BACnetContextTagUnsignedInteger('3', 'BACnetDataType.UNSIGNED_INTEGER')          lifetimeInSeconds           ]
-            [simple BACnetConstructedData('4')                                                       listOfValues                ]
+            [simple BACnetPropertyValues('4')                                                        listOfValues                ]
         ]
         ['0x03' BACnetUnconfirmedServiceRequestUnconfirmedEventNotification
         ]
@@ -521,16 +541,8 @@
         ]
         // TODO: implement other cases
         ['6' BACnetNotificationParametersComplexEventType(uint 4 peekedTagNumber)
-            [simple BACnetOpeningTag('peekedTagNumber', 'BACnetDataType.OPENING_TAG')
-                    innerOpeningTag
-            ]
-            [array  BACnetPropertyValue
-                    data
-                    terminated
-                    'STATIC_CALL("isBACnetConstructedDataClosingTag", readBuffer, peekedTagNumber)'
-            ]
-            [simple BACnetClosingTag('peekedTagNumber', 'BACnetDataType.CLOSING_TAG')
-                    innerClosingTag
+            [simple     BACnetPropertyValues('peekedTagNumber')
+                        listOfValues
             ]
         ]
         // TODO: implement other cases
@@ -653,6 +665,20 @@
     ]
 ]
 
+[type BACnetPropertyValues(uint 4 tagNumber)
+    [simple BACnetOpeningTag('tagNumber', 'BACnetDataType.OPENING_TAG')
+            innerOpeningTag
+    ]
+    [array  BACnetPropertyValue
+            data
+            terminated
+            'STATIC_CALL("isBACnetConstructedDataClosingTag", readBuffer, tagNumber)'
+    ]
+    [simple BACnetClosingTag('tagNumber', 'BACnetDataType.CLOSING_TAG')
+            innerClosingTag
+    ]
+]
+
 [type BACnetPropertyValue
     [simple   BACnetContextTagPropertyIdentifier('0', 'BACnetDataType.BACNET_PROPERTY_IDENTIFIER') propertyIdentifier  ]
     [optional BACnetContextTagUnsignedInteger('1', 'BACnetDataType.UNSIGNED_INTEGER')              propertyArrayIndex  ]

[plc4x] 02/02: fix(bacnet): enable tag numbers > 14

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 dc9b50eb64e1d6dfb993fe02c90bfddbb2f84c4f
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Tue Jan 11 20:02:56 2022 +0100

    fix(bacnet): enable tag numbers > 14
---
 .../resources/templates/go/model-template.go.ftlh  |  15 +-
 .../resources/templates/java/io-template.java.ftlh |   2 +-
 .../templates/java/model-template.java.ftlh        |   7 -
 .../plc4go/bacnetip/readwrite/ParserHelper.go      |   2 +
 .../plc4go/bacnetip/readwrite/XmlParserHelper.go   |  26 +-
 .../bacnetip/readwrite/model/BACnetAction.go       |   4 +-
 .../model/BACnetConstructedDataElement.go          |  37 ++-
 .../bacnetip/readwrite/model/BACnetContextTag.go   |  22 +-
 .../readwrite/model/BACnetContextTagEnumerated.go  |  27 +-
 .../model/BACnetNotificationParameters.go          |  30 +-
 .../BACnetNotificationParametersBufferReady.go     |  11 +-
 ...ACnetNotificationParametersChangeOfBitString.go |  11 +-
 .../BACnetNotificationParametersChangeOfState.go   |  11 +-
 .../BACnetNotificationParametersChangeOfValue.go   |  11 +-
 ...tNotificationParametersChangeOfValueNewValue.go |  30 +-
 ...onParametersChangeOfValueNewValueChangedBits.go |  11 +-
 ...nParametersChangeOfValueNewValueChangedValue.go |  11 +-
 ...BACnetNotificationParametersComplexEventType.go |  11 +-
 .../model/BACnetNotificationParametersExtended.go  |  11 +-
 .../BACnetNotificationParametersUnsignedRange.go   |  11 +-
 .../readwrite/model/BACnetPropertyStates.go        |  30 +-
 .../readwrite/model/BACnetPropertyStatesAction.go  |  11 +-
 .../readwrite/model/BACnetPropertyStatesBoolean.go |  11 +-
 .../bacnetip/readwrite/model/BACnetTagHeader.go    | 334 +++++++++++++++++++++
 .../bacnetip/readwrite/model/BACnetTimeStamp.go    |  30 +-
 .../readwrite/model/BACnetTimeStampDateTime.go     |  11 +-
 .../readwrite/model/BACnetTimeStampSequence.go     |  11 +-
 .../readwrite/model/BACnetTimeStampTime.go         |  11 +-
 .../plc4x/java/bacnetip/RandomPackagesTest.java    |   1 -
 .../spi/codegen/fields/FieldReaderOptional.java    |   4 +
 .../resources/protocols/bacnetip/bacnetip.mspec    | 111 ++++---
 31 files changed, 656 insertions(+), 210 deletions(-)

diff --git a/code-generation/language-go/src/main/resources/templates/go/model-template.go.ftlh b/code-generation/language-go/src/main/resources/templates/go/model-template.go.ftlh
index ab35616..c71066a 100644
--- a/code-generation/language-go/src/main/resources/templates/go/model-template.go.ftlh
+++ b/code-generation/language-go/src/main/resources/templates/go/model-template.go.ftlh
@@ -1191,21 +1191,10 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
                                 </#list>
                             </#if>
                         </#assign>
-				${peekField.name}, _err := ${typeName}Parse(readBuffer${refParams})
+				${peekField.name}, _ := ${typeName}Parse(readBuffer${refParams})
                     </...@compress>
-
-				switch {
-					case _err != nil && _err != utils.ParseAssertError:
-						return nil, errors.Wrap(_err, "Error parsing '${peekField.name}' field")<@emitImport import="github.com/pkg/errors" />
-					case _err == utils.ParseAssertError:
-						readBuffer.Reset(currentPos)
-					default:
-						${peekField.name} = Cast${helper.getLanguageTypeNameForField(field)}(_val)
-						if closeErr := readBuffer.CloseContext("${peekField.name}"); closeErr != nil {
-							return nil, closeErr
-						}
-				}
                 </#if>
+
 				readBuffer.Reset(currentPos)
                 <#break>
 		</#switch>
diff --git a/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
index 0628d51..d17a2c9 100644
--- a/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
+++ b/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
@@ -285,7 +285,7 @@ public class ${type.name}IO implements MessageInput<${type.name}> {
         <#assign validationField = field.asValidationField().orElseThrow()>
         // Validation
         if (!(${helper.toParseExpression(validationField, helper.boolTypeReference, validationField.getValidationExpression(), null)})) {
-            throw new RuntimeException(${validationField.getDescription().orElse("Validation failed")});
+            throw new ParseAssertException(${validationField.getDescription().orElse("Validation failed")});
         }
         <#break>
     <#case "peek">
diff --git a/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh
index db2951f..07dc000 100644
--- a/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh
+++ b/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh
@@ -298,13 +298,6 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                         ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = get${namedField.name?cap_first}();
                         writeBuffer.writeVirtual("${namedField.name}", ${namedField.name});
                         <#break>
-                    <#case "validation">
-                        <#assign validationField = field.asValidationField().orElseThrow()>
-                        // Validation
-                        if (!(${helper.toParseExpression(validationField, helper.boolTypeReference, validationField.getValidationExpression(), null)})) {
-                            throw new RuntimeException(${validationField.getDescription().orElse("Validation failed")});
-                        }
-                        <#break>
                 </#switch>
             </#list>
 
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/ParserHelper.go b/plc4go/internal/plc4go/bacnetip/readwrite/ParserHelper.go
index 498ce36..4315fd7 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/ParserHelper.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/ParserHelper.go
@@ -135,6 +135,8 @@ func (m BacnetipParserHelper) Parse(typeName string, arguments []string, io util
 			return nil, errors.Wrap(err, "Error parsing")
 		}
 		return model.BACnetPropertyValuesParse(io, tagNumber)
+	case "BACnetTagHeader":
+		return model.BACnetTagHeaderParse(io)
 	case "BACnetPropertyValue":
 		return model.BACnetPropertyValueParse(io)
 	case "BACnetServiceAck":
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/XmlParserHelper.go b/plc4go/internal/plc4go/bacnetip/readwrite/XmlParserHelper.go
index 3f4e0e9..37b3974 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/XmlParserHelper.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/XmlParserHelper.go
@@ -43,7 +43,7 @@ func init() {
 func (m BacnetipXmlParserHelper) Parse(typeName string, xmlString string, parserArguments ...string) (interface{}, error) {
 	switch typeName {
 	case "BACnetContextTag":
-		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 4)
+		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 8)
 		if err != nil {
 			return nil, err
 		}
@@ -51,7 +51,7 @@ func (m BacnetipXmlParserHelper) Parse(typeName string, xmlString string, parser
 		dataType := model.BACnetDataTypeByName(parserArguments[1])
 		return model.BACnetContextTagParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)), tagNumberArgument, dataType)
 	case "BACnetStatusFlags":
-		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 4)
+		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 8)
 		if err != nil {
 			return nil, err
 		}
@@ -65,28 +65,28 @@ func (m BacnetipXmlParserHelper) Parse(typeName string, xmlString string, parser
 		apduLength := uint16(parsedUint0)
 		return model.NLMParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)), apduLength)
 	case "BACnetNotificationParametersExtendedParameters":
-		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 4)
+		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 8)
 		if err != nil {
 			return nil, err
 		}
 		tagNumber := uint8(parsedUint0)
 		return model.BACnetNotificationParametersExtendedParametersParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)), tagNumber)
 	case "BACnetNotificationParametersChangeOfValueNewValue":
-		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 4)
+		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 8)
 		if err != nil {
 			return nil, err
 		}
 		tagNumber := uint8(parsedUint0)
 		return model.BACnetNotificationParametersChangeOfValueNewValueParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)), tagNumber)
 	case "BACnetPropertyStates":
-		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 4)
+		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 8)
 		if err != nil {
 			return nil, err
 		}
 		tagNumber := uint8(parsedUint0)
 		return model.BACnetPropertyStatesParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)), tagNumber)
 	case "BACnetConstructedData":
-		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 4)
+		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 8)
 		if err != nil {
 			return nil, err
 		}
@@ -104,7 +104,7 @@ func (m BacnetipXmlParserHelper) Parse(typeName string, xmlString string, parser
 	case "BVLC":
 		return model.BVLCParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
 	case "BACnetDateTime":
-		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 4)
+		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 8)
 		if err != nil {
 			return nil, err
 		}
@@ -120,14 +120,14 @@ func (m BacnetipXmlParserHelper) Parse(typeName string, xmlString string, parser
 	case "BACnetError":
 		return model.BACnetErrorParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
 	case "BACnetTimeStamp":
-		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 4)
+		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 8)
 		if err != nil {
 			return nil, err
 		}
 		tagNumber := uint8(parsedUint0)
 		return model.BACnetTimeStampParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)), tagNumber)
 	case "BACnetNotificationParameters":
-		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 4)
+		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 8)
 		if err != nil {
 			return nil, err
 		}
@@ -145,7 +145,7 @@ func (m BacnetipXmlParserHelper) Parse(typeName string, xmlString string, parser
 	case "BACnetApplicationTag":
 		return model.BACnetApplicationTagParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
 	case "BACnetDeviceObjectPropertyReference":
-		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 4)
+		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 8)
 		if err != nil {
 			return nil, err
 		}
@@ -154,18 +154,20 @@ func (m BacnetipXmlParserHelper) Parse(typeName string, xmlString string, parser
 	case "BACnetConstructedDataElement":
 		return model.BACnetConstructedDataElementParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
 	case "BACnetPropertyValues":
-		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 4)
+		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 8)
 		if err != nil {
 			return nil, err
 		}
 		tagNumber := uint8(parsedUint0)
 		return model.BACnetPropertyValuesParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)), tagNumber)
+	case "BACnetTagHeader":
+		return model.BACnetTagHeaderParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
 	case "BACnetPropertyValue":
 		return model.BACnetPropertyValueParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
 	case "BACnetServiceAck":
 		return model.BACnetServiceAckParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
 	case "BACnetAction":
-		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 4)
+		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 8)
 		if err != nil {
 			return nil, err
 		}
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetAction.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetAction.go
index ae79984..5ba58ab 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetAction.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetAction.go
@@ -111,11 +111,11 @@ func BACnetActionParse(readBuffer utils.ReadBuffer, tagNumber uint8) (*BACnetAct
 	}
 
 	// Virtual field
-	_isDirect := bool(((*rawData).Data[0]) == (0))
+	_isDirect := bool(bool(bool((rawData) != (nil))) && bool(bool((len((*rawData).Data)) == (1)))) && bool(bool(((*rawData).Data[0]) == (0)))
 	isDirect := bool(_isDirect)
 
 	// Virtual field
-	_isReverse := bool(((*rawData).Data[1]) == (1))
+	_isReverse := bool(bool(bool((rawData) != (nil))) && bool(bool((len((*rawData).Data)) == (1)))) && bool(bool(((*rawData).Data[0]) == (1)))
 	isReverse := bool(_isReverse)
 
 	if closeErr := readBuffer.CloseContext("BACnetAction"); closeErr != nil {
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConstructedDataElement.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConstructedDataElement.go
index d76b199..891d565 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConstructedDataElement.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConstructedDataElement.go
@@ -28,10 +28,11 @@ import (
 
 // The data-structure of this message
 type BACnetConstructedDataElement struct {
-	PeekedByte        byte
+	PeekedTagHeader   *BACnetTagHeader
 	ApplicationTag    *BACnetApplicationTag
 	ContextTag        *BACnetContextTag
 	ConstructedData   *BACnetConstructedData
+	PeekedTagNumber   uint8
 	IsApplicationTag  bool
 	IsConstructedData bool
 	IsContextTag      bool
@@ -44,8 +45,8 @@ type IBACnetConstructedDataElement interface {
 	Serialize(writeBuffer utils.WriteBuffer) error
 }
 
-func NewBACnetConstructedDataElement(peekedByte byte, applicationTag *BACnetApplicationTag, contextTag *BACnetContextTag, constructedData *BACnetConstructedData, isApplicationTag bool, isConstructedData bool, isContextTag bool) *BACnetConstructedDataElement {
-	return &BACnetConstructedDataElement{PeekedByte: peekedByte, ApplicationTag: applicationTag, ContextTag: contextTag, ConstructedData: constructedData, IsApplicationTag: isApplicationTag, IsConstructedData: isConstructedData, IsContextTag: isContextTag}
+func NewBACnetConstructedDataElement(peekedTagHeader *BACnetTagHeader, applicationTag *BACnetApplicationTag, contextTag *BACnetContextTag, constructedData *BACnetConstructedData, peekedTagNumber uint8, isApplicationTag bool, isConstructedData bool, isContextTag bool) *BACnetConstructedDataElement {
+	return &BACnetConstructedDataElement{PeekedTagHeader: peekedTagHeader, ApplicationTag: applicationTag, ContextTag: contextTag, ConstructedData: constructedData, PeekedTagNumber: peekedTagNumber, IsApplicationTag: isApplicationTag, IsConstructedData: isConstructedData, IsContextTag: isContextTag}
 }
 
 func CastBACnetConstructedDataElement(structType interface{}) *BACnetConstructedDataElement {
@@ -78,6 +79,8 @@ func (m *BACnetConstructedDataElement) LengthInBitsConditional(lastItem bool) ui
 
 	// A virtual field doesn't have any in- or output.
 
+	// A virtual field doesn't have any in- or output.
+
 	// Optional Field (applicationTag)
 	if m.ApplicationTag != nil {
 		lengthInBits += (*m.ApplicationTag).LengthInBits()
@@ -105,24 +108,28 @@ func BACnetConstructedDataElementParse(readBuffer utils.ReadBuffer) (*BACnetCons
 		return nil, pullErr
 	}
 
-	// Peek Field (peekedByte)
+	// Peek Field (peekedTagHeader)
 	currentPos := readBuffer.GetPos()
-	peekedByte, _err := readBuffer.ReadByte("peekedByte")
-	if _err != nil {
-		return nil, errors.Wrap(_err, "Error parsing 'peekedByte' field")
+	if pullErr := readBuffer.PullContext("peekedTagHeader"); pullErr != nil {
+		return nil, pullErr
 	}
+	peekedTagHeader, _ := BACnetTagHeaderParse(readBuffer)
 	readBuffer.Reset(currentPos)
 
 	// Virtual field
-	_isApplicationTag := IsApplicationTag(peekedByte)
+	_peekedTagNumber := peekedTagHeader.ActualTagNumber
+	peekedTagNumber := uint8(_peekedTagNumber)
+
+	// Virtual field
+	_isApplicationTag := bool((peekedTagHeader.TagClass) == (TagClass_APPLICATION_TAGS))
 	isApplicationTag := bool(_isApplicationTag)
 
 	// Virtual field
-	_isConstructedData := IsConstructedData(peekedByte)
+	_isConstructedData := bool(!(isApplicationTag)) && bool(bool((peekedTagHeader.ActualLength) == (0x6)))
 	isConstructedData := bool(_isConstructedData)
 
 	// Virtual field
-	_isContextTag := bool(!(isConstructedData)) && bool(IsContextTag(peekedByte))
+	_isContextTag := bool(!(isConstructedData)) && bool(!(isApplicationTag))
 	isContextTag := bool(_isContextTag)
 
 	// Optional Field (applicationTag) (Can be skipped, if a given expression evaluates to false)
@@ -153,7 +160,7 @@ func BACnetConstructedDataElementParse(readBuffer utils.ReadBuffer) (*BACnetCons
 		if pullErr := readBuffer.PullContext("contextTag"); pullErr != nil {
 			return nil, pullErr
 		}
-		_val, _err := BACnetContextTagParse(readBuffer, uint8(uint8(uint8(peekedByte)&uint8(0xF0)))>>uint8(uint8(4)), GuessDataType())
+		_val, _err := BACnetContextTagParse(readBuffer, peekedTagNumber, GuessDataType())
 		switch {
 		case _err != nil && _err != utils.ParseAssertError:
 			return nil, errors.Wrap(_err, "Error parsing 'contextTag' field")
@@ -174,7 +181,7 @@ func BACnetConstructedDataElementParse(readBuffer utils.ReadBuffer) (*BACnetCons
 		if pullErr := readBuffer.PullContext("constructedData"); pullErr != nil {
 			return nil, pullErr
 		}
-		_val, _err := BACnetConstructedDataParse(readBuffer, uint8(uint8(uint8(peekedByte)&uint8(0xF0)))>>uint8(uint8(4)))
+		_val, _err := BACnetConstructedDataParse(readBuffer, peekedTagNumber)
 		switch {
 		case _err != nil && _err != utils.ParseAssertError:
 			return nil, errors.Wrap(_err, "Error parsing 'constructedData' field")
@@ -193,7 +200,7 @@ func BACnetConstructedDataElementParse(readBuffer utils.ReadBuffer) (*BACnetCons
 	}
 
 	// Create the instance
-	return NewBACnetConstructedDataElement(peekedByte, applicationTag, contextTag, constructedData, isApplicationTag, isConstructedData, isContextTag), nil
+	return NewBACnetConstructedDataElement(peekedTagHeader, applicationTag, contextTag, constructedData, peekedTagNumber, isApplicationTag, isConstructedData, isContextTag), nil
 }
 
 func (m *BACnetConstructedDataElement) Serialize(writeBuffer utils.WriteBuffer) error {
@@ -201,6 +208,10 @@ func (m *BACnetConstructedDataElement) Serialize(writeBuffer utils.WriteBuffer)
 		return pushErr
 	}
 	// Virtual field
+	if _peekedTagNumberErr := writeBuffer.WriteVirtual("peekedTagNumber", m.PeekedTagNumber); _peekedTagNumberErr != nil {
+		return errors.Wrap(_peekedTagNumberErr, "Error serializing 'peekedTagNumber' field")
+	}
+	// Virtual field
 	if _isApplicationTagErr := writeBuffer.WriteVirtual("isApplicationTag", m.IsApplicationTag); _isApplicationTagErr != nil {
 		return errors.Wrap(_isApplicationTagErr, "Error serializing 'isApplicationTag' field")
 	}
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetContextTag.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetContextTag.go
index 1492590..b17c13d 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetContextTag.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetContextTag.go
@@ -92,6 +92,9 @@ func (m *BACnetContextTag) LengthInBitsConditional(lastItem bool) uint16 {
 func (m *BACnetContextTag) ParentLengthInBits() uint16 {
 	lengthInBits := uint16(0)
 
+	// Simple field (tagNumber)
+	lengthInBits += 4
+
 	// Simple field (lengthValueType)
 	lengthInBits += 3
 
@@ -131,14 +134,12 @@ func BACnetContextTagParse(readBuffer utils.ReadBuffer, tagNumberArgument uint8,
 		return nil, pullErr
 	}
 
-	// Assert Field (tagNumber) (Can be skipped, if a given expression evaluates to false)
-	tagNumber, _err := readBuffer.ReadUint8("tagNumber", 4)
-	if _err != nil {
-		return nil, errors.Wrap(_err, "Error parsing 'tagNumber' field")
-	}
-	if tagNumber != tagNumberArgument {
-		return nil, utils.ParseAssertError
+	// Simple Field (tagNumber)
+	_tagNumber, _tagNumberErr := readBuffer.ReadUint8("tagNumber", 4)
+	if _tagNumberErr != nil {
+		return nil, errors.Wrap(_tagNumberErr, "Error parsing 'tagNumber' field")
 	}
+	tagNumber := _tagNumber
 
 	// Assert Field (tagClass) (Can be skipped, if a given expression evaluates to false)
 	tagClass, _err := TagClassParse(readBuffer)
@@ -278,6 +279,13 @@ func (m *BACnetContextTag) SerializeParent(writeBuffer utils.WriteBuffer, child
 		return pushErr
 	}
 
+	// Simple Field (tagNumber)
+	tagNumber := uint8(m.TagNumber)
+	_tagNumberErr := writeBuffer.WriteUint8("tagNumber", 4, (tagNumber))
+	if _tagNumberErr != nil {
+		return errors.Wrap(_tagNumberErr, "Error serializing 'tagNumber' field")
+	}
+
 	// Simple Field (lengthValueType)
 	lengthValueType := uint8(m.LengthValueType)
 	_lengthValueTypeErr := writeBuffer.WriteUint8("lengthValueType", 3, (lengthValueType))
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetContextTagEnumerated.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetContextTagEnumerated.go
index f9f8903..1cd1c1c 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetContextTagEnumerated.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetContextTagEnumerated.go
@@ -29,8 +29,7 @@ import (
 // The data-structure of this message
 type BACnetContextTagEnumerated struct {
 	*BACnetContextTag
-	Data              []int8
-	ActualLengthInBit uint16
+	Data []int8
 }
 
 // The corresponding interface
@@ -57,11 +56,10 @@ func (m *BACnetContextTagEnumerated) InitializeParent(parent *BACnetContextTag,
 	m.ExtExtExtLength = extExtExtLength
 }
 
-func NewBACnetContextTagEnumerated(data []int8, actualLengthInBit uint16, tagNumber uint8, tagClass TagClass, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, actualTagNumber uint8, actualLength uint32) *BACnetContextTag {
+func NewBACnetContextTagEnumerated(data []int8, tagNumber uint8, tagClass TagClass, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, actualTagNumber uint8, actualLength uint32) *BACnetContextTag {
 	child := &BACnetContextTagEnumerated{
-		Data:              data,
-		ActualLengthInBit: actualLengthInBit,
-		BACnetContextTag:  NewBACnetContextTag(tagNumber, tagClass, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength, actualTagNumber, actualLength),
+		Data:             data,
+		BACnetContextTag: NewBACnetContextTag(tagNumber, tagClass, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength, actualTagNumber, actualLength),
 	}
 	child.Child = child
 	return child.BACnetContextTag
@@ -97,8 +95,6 @@ func (m *BACnetContextTagEnumerated) LengthInBits() uint16 {
 func (m *BACnetContextTagEnumerated) LengthInBitsConditional(lastItem bool) uint16 {
 	lengthInBits := uint16(m.ParentLengthInBits())
 
-	// A virtual field doesn't have any in- or output.
-
 	// Array field
 	if len(m.Data) > 0 {
 		lengthInBits += 8 * uint16(len(m.Data))
@@ -116,10 +112,6 @@ func BACnetContextTagEnumeratedParse(readBuffer utils.ReadBuffer, tagNumberArgum
 		return nil, pullErr
 	}
 
-	// Virtual field
-	_actualLengthInBit := uint16(actualLength) * uint16(uint16(8))
-	actualLengthInBit := uint16(_actualLengthInBit)
-
 	// Array field (data)
 	if pullErr := readBuffer.PullContext("data", utils.WithRenderAsList(true)); pullErr != nil {
 		return nil, pullErr
@@ -127,7 +119,7 @@ func BACnetContextTagEnumeratedParse(readBuffer utils.ReadBuffer, tagNumberArgum
 	// Length array
 	data := make([]int8, 0)
 	{
-		_dataLength := actualLengthInBit
+		_dataLength := actualLength
 		_dataEndPos := readBuffer.GetPos() + uint16(_dataLength)
 		for readBuffer.GetPos() < _dataEndPos {
 			_item, _err := readBuffer.ReadInt8("", 8)
@@ -147,9 +139,8 @@ func BACnetContextTagEnumeratedParse(readBuffer utils.ReadBuffer, tagNumberArgum
 
 	// Create a partially initialized instance
 	_child := &BACnetContextTagEnumerated{
-		Data:              data,
-		ActualLengthInBit: actualLengthInBit,
-		BACnetContextTag:  &BACnetContextTag{},
+		Data:             data,
+		BACnetContextTag: &BACnetContextTag{},
 	}
 	_child.BACnetContextTag.Child = _child
 	return _child.BACnetContextTag, nil
@@ -160,10 +151,6 @@ func (m *BACnetContextTagEnumerated) Serialize(writeBuffer utils.WriteBuffer) er
 		if pushErr := writeBuffer.PushContext("BACnetContextTagEnumerated"); pushErr != nil {
 			return pushErr
 		}
-		// Virtual field
-		if _actualLengthInBitErr := writeBuffer.WriteVirtual("actualLengthInBit", m.ActualLengthInBit); _actualLengthInBitErr != nil {
-			return errors.Wrap(_actualLengthInBitErr, "Error serializing 'actualLengthInBit' field")
-		}
 
 		// Array Field (data)
 		if m.Data != nil {
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParameters.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParameters.go
index ce35b28..2aa24cb 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParameters.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParameters.go
@@ -29,13 +29,15 @@ import (
 // The data-structure of this message
 type BACnetNotificationParameters struct {
 	OpeningTag      *BACnetOpeningTag
-	PeekedTagNumber uint8
+	PeekedTagHeader *BACnetTagHeader
 	ClosingTag      *BACnetClosingTag
+	PeekedTagNumber uint8
 	Child           IBACnetNotificationParametersChild
 }
 
 // The corresponding interface
 type IBACnetNotificationParameters interface {
+	PeekedTagNumber() uint8
 	LengthInBytes() uint16
 	LengthInBits() uint16
 	Serialize(writeBuffer utils.WriteBuffer) error
@@ -48,13 +50,13 @@ type IBACnetNotificationParametersParent interface {
 
 type IBACnetNotificationParametersChild interface {
 	Serialize(writeBuffer utils.WriteBuffer) error
-	InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag)
+	InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8)
 	GetTypeName() string
 	IBACnetNotificationParameters
 }
 
-func NewBACnetNotificationParameters(openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetNotificationParameters {
-	return &BACnetNotificationParameters{OpeningTag: openingTag, PeekedTagNumber: peekedTagNumber, ClosingTag: closingTag}
+func NewBACnetNotificationParameters(openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetNotificationParameters {
+	return &BACnetNotificationParameters{OpeningTag: openingTag, PeekedTagHeader: peekedTagHeader, ClosingTag: closingTag, PeekedTagNumber: peekedTagNumber}
 }
 
 func CastBACnetNotificationParameters(structType interface{}) *BACnetNotificationParameters {
@@ -88,6 +90,8 @@ func (m *BACnetNotificationParameters) ParentLengthInBits() uint16 {
 	// Simple field (openingTag)
 	lengthInBits += m.OpeningTag.LengthInBits()
 
+	// A virtual field doesn't have any in- or output.
+
 	// Simple field (closingTag)
 	lengthInBits += m.ClosingTag.LengthInBits()
 
@@ -116,14 +120,18 @@ func BACnetNotificationParametersParse(readBuffer utils.ReadBuffer, tagNumber ui
 		return nil, closeErr
 	}
 
-	// Peek Field (peekedTagNumber)
+	// Peek Field (peekedTagHeader)
 	currentPos := readBuffer.GetPos()
-	peekedTagNumber, _err := readBuffer.ReadUint8("peekedTagNumber", 4)
-	if _err != nil {
-		return nil, errors.Wrap(_err, "Error parsing 'peekedTagNumber' field")
+	if pullErr := readBuffer.PullContext("peekedTagHeader"); pullErr != nil {
+		return nil, pullErr
 	}
+	peekedTagHeader, _ := BACnetTagHeaderParse(readBuffer)
 	readBuffer.Reset(currentPos)
 
+	// Virtual field
+	_peekedTagNumber := peekedTagHeader.ActualTagNumber
+	peekedTagNumber := uint8(_peekedTagNumber)
+
 	// Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
 	var _parent *BACnetNotificationParameters
 	var typeSwitchError error
@@ -168,7 +176,7 @@ func BACnetNotificationParametersParse(readBuffer utils.ReadBuffer, tagNumber ui
 	}
 
 	// Finish initializing
-	_parent.Child.InitializeParent(_parent, openingTag, peekedTagNumber, closingTag)
+	_parent.Child.InitializeParent(_parent, openingTag, peekedTagHeader, closingTag, peekedTagNumber)
 	return _parent, nil
 }
 
@@ -192,6 +200,10 @@ func (m *BACnetNotificationParameters) SerializeParent(writeBuffer utils.WriteBu
 	if _openingTagErr != nil {
 		return errors.Wrap(_openingTagErr, "Error serializing 'openingTag' field")
 	}
+	// Virtual field
+	if _peekedTagNumberErr := writeBuffer.WriteVirtual("peekedTagNumber", m.PeekedTagNumber); _peekedTagNumberErr != nil {
+		return errors.Wrap(_peekedTagNumberErr, "Error serializing 'peekedTagNumber' field")
+	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
 	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersBufferReady.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersBufferReady.go
index ba6d3fe..5aabfb2 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersBufferReady.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersBufferReady.go
@@ -46,21 +46,24 @@ type IBACnetNotificationParametersBufferReady interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
+func (m *BACnetNotificationParametersBufferReady) PeekedTagNumber() uint8 {
+	return uint8(10)
+}
 
-func (m *BACnetNotificationParametersBufferReady) InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) {
+func (m *BACnetNotificationParametersBufferReady) InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) {
 	m.OpeningTag = openingTag
-	m.PeekedTagNumber = peekedTagNumber
+	m.PeekedTagHeader = peekedTagHeader
 	m.ClosingTag = closingTag
 }
 
-func NewBACnetNotificationParametersBufferReady(innerOpeningTag *BACnetOpeningTag, bufferProperty *BACnetDeviceObjectPropertyReference, previousNotification *BACnetContextTagUnsignedInteger, currentNotification *BACnetContextTagUnsignedInteger, innerClosingTag *BACnetClosingTag, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetNotificationParameters {
+func NewBACnetNotificationParametersBufferReady(innerOpeningTag *BACnetOpeningTag, bufferProperty *BACnetDeviceObjectPropertyReference, previousNotification *BACnetContextTagUnsignedInteger, currentNotification *BACnetContextTagUnsignedInteger, innerClosingTag *BACnetClosingTag, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetNotificationParameters {
 	child := &BACnetNotificationParametersBufferReady{
 		InnerOpeningTag:              innerOpeningTag,
 		BufferProperty:               bufferProperty,
 		PreviousNotification:         previousNotification,
 		CurrentNotification:          currentNotification,
 		InnerClosingTag:              innerClosingTag,
-		BACnetNotificationParameters: NewBACnetNotificationParameters(openingTag, peekedTagNumber, closingTag),
+		BACnetNotificationParameters: NewBACnetNotificationParameters(openingTag, peekedTagHeader, closingTag, peekedTagNumber),
 	}
 	child.Child = child
 	return child.BACnetNotificationParameters
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfBitString.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfBitString.go
index 48b0cb6..7162494 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfBitString.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfBitString.go
@@ -45,20 +45,23 @@ type IBACnetNotificationParametersChangeOfBitString interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
+func (m *BACnetNotificationParametersChangeOfBitString) PeekedTagNumber() uint8 {
+	return uint8(0)
+}
 
-func (m *BACnetNotificationParametersChangeOfBitString) InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) {
+func (m *BACnetNotificationParametersChangeOfBitString) InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) {
 	m.OpeningTag = openingTag
-	m.PeekedTagNumber = peekedTagNumber
+	m.PeekedTagHeader = peekedTagHeader
 	m.ClosingTag = closingTag
 }
 
-func NewBACnetNotificationParametersChangeOfBitString(innerOpeningTag *BACnetOpeningTag, changeOfBitString *BACnetContextTagBitString, statusFlags *BACnetStatusFlags, innerClosingTag *BACnetClosingTag, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetNotificationParameters {
+func NewBACnetNotificationParametersChangeOfBitString(innerOpeningTag *BACnetOpeningTag, changeOfBitString *BACnetContextTagBitString, statusFlags *BACnetStatusFlags, innerClosingTag *BACnetClosingTag, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetNotificationParameters {
 	child := &BACnetNotificationParametersChangeOfBitString{
 		InnerOpeningTag:              innerOpeningTag,
 		ChangeOfBitString:            changeOfBitString,
 		StatusFlags:                  statusFlags,
 		InnerClosingTag:              innerClosingTag,
-		BACnetNotificationParameters: NewBACnetNotificationParameters(openingTag, peekedTagNumber, closingTag),
+		BACnetNotificationParameters: NewBACnetNotificationParameters(openingTag, peekedTagHeader, closingTag, peekedTagNumber),
 	}
 	child.Child = child
 	return child.BACnetNotificationParameters
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfState.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfState.go
index 89f7a7a..dca3fdc 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfState.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfState.go
@@ -45,20 +45,23 @@ type IBACnetNotificationParametersChangeOfState interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
+func (m *BACnetNotificationParametersChangeOfState) PeekedTagNumber() uint8 {
+	return uint8(1)
+}
 
-func (m *BACnetNotificationParametersChangeOfState) InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) {
+func (m *BACnetNotificationParametersChangeOfState) InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) {
 	m.OpeningTag = openingTag
-	m.PeekedTagNumber = peekedTagNumber
+	m.PeekedTagHeader = peekedTagHeader
 	m.ClosingTag = closingTag
 }
 
-func NewBACnetNotificationParametersChangeOfState(innerOpeningTag *BACnetOpeningTag, changeOfState *BACnetPropertyStates, statusFlags *BACnetStatusFlags, innerClosingTag *BACnetClosingTag, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetNotificationParameters {
+func NewBACnetNotificationParametersChangeOfState(innerOpeningTag *BACnetOpeningTag, changeOfState *BACnetPropertyStates, statusFlags *BACnetStatusFlags, innerClosingTag *BACnetClosingTag, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetNotificationParameters {
 	child := &BACnetNotificationParametersChangeOfState{
 		InnerOpeningTag:              innerOpeningTag,
 		ChangeOfState:                changeOfState,
 		StatusFlags:                  statusFlags,
 		InnerClosingTag:              innerClosingTag,
-		BACnetNotificationParameters: NewBACnetNotificationParameters(openingTag, peekedTagNumber, closingTag),
+		BACnetNotificationParameters: NewBACnetNotificationParameters(openingTag, peekedTagHeader, closingTag, peekedTagNumber),
 	}
 	child.Child = child
 	return child.BACnetNotificationParameters
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValue.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValue.go
index 4075a51..a2075ae 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValue.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValue.go
@@ -45,20 +45,23 @@ type IBACnetNotificationParametersChangeOfValue interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
+func (m *BACnetNotificationParametersChangeOfValue) PeekedTagNumber() uint8 {
+	return uint8(2)
+}
 
-func (m *BACnetNotificationParametersChangeOfValue) InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) {
+func (m *BACnetNotificationParametersChangeOfValue) InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) {
 	m.OpeningTag = openingTag
-	m.PeekedTagNumber = peekedTagNumber
+	m.PeekedTagHeader = peekedTagHeader
 	m.ClosingTag = closingTag
 }
 
-func NewBACnetNotificationParametersChangeOfValue(innerOpeningTag *BACnetOpeningTag, newValue *BACnetNotificationParametersChangeOfValueNewValue, statusFlags *BACnetStatusFlags, innerClosingTag *BACnetClosingTag, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetNotificationParameters {
+func NewBACnetNotificationParametersChangeOfValue(innerOpeningTag *BACnetOpeningTag, newValue *BACnetNotificationParametersChangeOfValueNewValue, statusFlags *BACnetStatusFlags, innerClosingTag *BACnetClosingTag, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetNotificationParameters {
 	child := &BACnetNotificationParametersChangeOfValue{
 		InnerOpeningTag:              innerOpeningTag,
 		NewValue:                     newValue,
 		StatusFlags:                  statusFlags,
 		InnerClosingTag:              innerClosingTag,
-		BACnetNotificationParameters: NewBACnetNotificationParameters(openingTag, peekedTagNumber, closingTag),
+		BACnetNotificationParameters: NewBACnetNotificationParameters(openingTag, peekedTagHeader, closingTag, peekedTagNumber),
 	}
 	child.Child = child
 	return child.BACnetNotificationParameters
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValueNewValue.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValueNewValue.go
index 86b493e..95537c1 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValueNewValue.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValueNewValue.go
@@ -29,13 +29,15 @@ import (
 // The data-structure of this message
 type BACnetNotificationParametersChangeOfValueNewValue struct {
 	OpeningTag      *BACnetOpeningTag
-	PeekedTagNumber uint8
+	PeekedTagHeader *BACnetTagHeader
 	ClosingTag      *BACnetClosingTag
+	PeekedTagNumber uint8
 	Child           IBACnetNotificationParametersChangeOfValueNewValueChild
 }
 
 // The corresponding interface
 type IBACnetNotificationParametersChangeOfValueNewValue interface {
+	PeekedTagNumber() uint8
 	LengthInBytes() uint16
 	LengthInBits() uint16
 	Serialize(writeBuffer utils.WriteBuffer) error
@@ -48,13 +50,13 @@ type IBACnetNotificationParametersChangeOfValueNewValueParent interface {
 
 type IBACnetNotificationParametersChangeOfValueNewValueChild interface {
 	Serialize(writeBuffer utils.WriteBuffer) error
-	InitializeParent(parent *BACnetNotificationParametersChangeOfValueNewValue, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag)
+	InitializeParent(parent *BACnetNotificationParametersChangeOfValueNewValue, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8)
 	GetTypeName() string
 	IBACnetNotificationParametersChangeOfValueNewValue
 }
 
-func NewBACnetNotificationParametersChangeOfValueNewValue(openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetNotificationParametersChangeOfValueNewValue {
-	return &BACnetNotificationParametersChangeOfValueNewValue{OpeningTag: openingTag, PeekedTagNumber: peekedTagNumber, ClosingTag: closingTag}
+func NewBACnetNotificationParametersChangeOfValueNewValue(openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetNotificationParametersChangeOfValueNewValue {
+	return &BACnetNotificationParametersChangeOfValueNewValue{OpeningTag: openingTag, PeekedTagHeader: peekedTagHeader, ClosingTag: closingTag, PeekedTagNumber: peekedTagNumber}
 }
 
 func CastBACnetNotificationParametersChangeOfValueNewValue(structType interface{}) *BACnetNotificationParametersChangeOfValueNewValue {
@@ -88,6 +90,8 @@ func (m *BACnetNotificationParametersChangeOfValueNewValue) ParentLengthInBits()
 	// Simple field (openingTag)
 	lengthInBits += m.OpeningTag.LengthInBits()
 
+	// A virtual field doesn't have any in- or output.
+
 	// Simple field (closingTag)
 	lengthInBits += m.ClosingTag.LengthInBits()
 
@@ -116,14 +120,18 @@ func BACnetNotificationParametersChangeOfValueNewValueParse(readBuffer utils.Rea
 		return nil, closeErr
 	}
 
-	// Peek Field (peekedTagNumber)
+	// Peek Field (peekedTagHeader)
 	currentPos := readBuffer.GetPos()
-	peekedTagNumber, _err := readBuffer.ReadUint8("peekedTagNumber", 4)
-	if _err != nil {
-		return nil, errors.Wrap(_err, "Error parsing 'peekedTagNumber' field")
+	if pullErr := readBuffer.PullContext("peekedTagHeader"); pullErr != nil {
+		return nil, pullErr
 	}
+	peekedTagHeader, _ := BACnetTagHeaderParse(readBuffer)
 	readBuffer.Reset(currentPos)
 
+	// Virtual field
+	_peekedTagNumber := peekedTagHeader.ActualTagNumber
+	peekedTagNumber := uint8(_peekedTagNumber)
+
 	// Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
 	var _parent *BACnetNotificationParametersChangeOfValueNewValue
 	var typeSwitchError error
@@ -158,7 +166,7 @@ func BACnetNotificationParametersChangeOfValueNewValueParse(readBuffer utils.Rea
 	}
 
 	// Finish initializing
-	_parent.Child.InitializeParent(_parent, openingTag, peekedTagNumber, closingTag)
+	_parent.Child.InitializeParent(_parent, openingTag, peekedTagHeader, closingTag, peekedTagNumber)
 	return _parent, nil
 }
 
@@ -182,6 +190,10 @@ func (m *BACnetNotificationParametersChangeOfValueNewValue) SerializeParent(writ
 	if _openingTagErr != nil {
 		return errors.Wrap(_openingTagErr, "Error serializing 'openingTag' field")
 	}
+	// Virtual field
+	if _peekedTagNumberErr := writeBuffer.WriteVirtual("peekedTagNumber", m.PeekedTagNumber); _peekedTagNumberErr != nil {
+		return errors.Wrap(_peekedTagNumberErr, "Error serializing 'peekedTagNumber' field")
+	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
 	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValueNewValueChangedBits.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValueNewValueChangedBits.go
index a826431..60413dc 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValueNewValueChangedBits.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValueNewValueChangedBits.go
@@ -42,17 +42,20 @@ type IBACnetNotificationParametersChangeOfValueNewValueChangedBits interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
+func (m *BACnetNotificationParametersChangeOfValueNewValueChangedBits) PeekedTagNumber() uint8 {
+	return uint8(0)
+}
 
-func (m *BACnetNotificationParametersChangeOfValueNewValueChangedBits) InitializeParent(parent *BACnetNotificationParametersChangeOfValueNewValue, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) {
+func (m *BACnetNotificationParametersChangeOfValueNewValueChangedBits) InitializeParent(parent *BACnetNotificationParametersChangeOfValueNewValue, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) {
 	m.OpeningTag = openingTag
-	m.PeekedTagNumber = peekedTagNumber
+	m.PeekedTagHeader = peekedTagHeader
 	m.ClosingTag = closingTag
 }
 
-func NewBACnetNotificationParametersChangeOfValueNewValueChangedBits(changedBits *BACnetContextTagBitString, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetNotificationParametersChangeOfValueNewValue {
+func NewBACnetNotificationParametersChangeOfValueNewValueChangedBits(changedBits *BACnetContextTagBitString, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetNotificationParametersChangeOfValueNewValue {
 	child := &BACnetNotificationParametersChangeOfValueNewValueChangedBits{
 		ChangedBits: changedBits,
-		BACnetNotificationParametersChangeOfValueNewValue: NewBACnetNotificationParametersChangeOfValueNewValue(openingTag, peekedTagNumber, closingTag),
+		BACnetNotificationParametersChangeOfValueNewValue: NewBACnetNotificationParametersChangeOfValueNewValue(openingTag, peekedTagHeader, closingTag, peekedTagNumber),
 	}
 	child.Child = child
 	return child.BACnetNotificationParametersChangeOfValueNewValue
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValueNewValueChangedValue.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValueNewValueChangedValue.go
index ec080e6..14ea42f 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValueNewValueChangedValue.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersChangeOfValueNewValueChangedValue.go
@@ -42,17 +42,20 @@ type IBACnetNotificationParametersChangeOfValueNewValueChangedValue interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
+func (m *BACnetNotificationParametersChangeOfValueNewValueChangedValue) PeekedTagNumber() uint8 {
+	return uint8(1)
+}
 
-func (m *BACnetNotificationParametersChangeOfValueNewValueChangedValue) InitializeParent(parent *BACnetNotificationParametersChangeOfValueNewValue, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) {
+func (m *BACnetNotificationParametersChangeOfValueNewValueChangedValue) InitializeParent(parent *BACnetNotificationParametersChangeOfValueNewValue, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) {
 	m.OpeningTag = openingTag
-	m.PeekedTagNumber = peekedTagNumber
+	m.PeekedTagHeader = peekedTagHeader
 	m.ClosingTag = closingTag
 }
 
-func NewBACnetNotificationParametersChangeOfValueNewValueChangedValue(changedValue *BACnetContextTagReal, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetNotificationParametersChangeOfValueNewValue {
+func NewBACnetNotificationParametersChangeOfValueNewValueChangedValue(changedValue *BACnetContextTagReal, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetNotificationParametersChangeOfValueNewValue {
 	child := &BACnetNotificationParametersChangeOfValueNewValueChangedValue{
 		ChangedValue: changedValue,
-		BACnetNotificationParametersChangeOfValueNewValue: NewBACnetNotificationParametersChangeOfValueNewValue(openingTag, peekedTagNumber, closingTag),
+		BACnetNotificationParametersChangeOfValueNewValue: NewBACnetNotificationParametersChangeOfValueNewValue(openingTag, peekedTagHeader, closingTag, peekedTagNumber),
 	}
 	child.Child = child
 	return child.BACnetNotificationParametersChangeOfValueNewValue
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersComplexEventType.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersComplexEventType.go
index 4c971ea..b0c8168 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersComplexEventType.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersComplexEventType.go
@@ -42,17 +42,20 @@ type IBACnetNotificationParametersComplexEventType interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
+func (m *BACnetNotificationParametersComplexEventType) PeekedTagNumber() uint8 {
+	return uint8(6)
+}
 
-func (m *BACnetNotificationParametersComplexEventType) InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) {
+func (m *BACnetNotificationParametersComplexEventType) InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) {
 	m.OpeningTag = openingTag
-	m.PeekedTagNumber = peekedTagNumber
+	m.PeekedTagHeader = peekedTagHeader
 	m.ClosingTag = closingTag
 }
 
-func NewBACnetNotificationParametersComplexEventType(listOfValues *BACnetPropertyValues, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetNotificationParameters {
+func NewBACnetNotificationParametersComplexEventType(listOfValues *BACnetPropertyValues, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetNotificationParameters {
 	child := &BACnetNotificationParametersComplexEventType{
 		ListOfValues:                 listOfValues,
-		BACnetNotificationParameters: NewBACnetNotificationParameters(openingTag, peekedTagNumber, closingTag),
+		BACnetNotificationParameters: NewBACnetNotificationParameters(openingTag, peekedTagHeader, closingTag, peekedTagNumber),
 	}
 	child.Child = child
 	return child.BACnetNotificationParameters
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersExtended.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersExtended.go
index 43e45ed..7996e22 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersExtended.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersExtended.go
@@ -46,21 +46,24 @@ type IBACnetNotificationParametersExtended interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
+func (m *BACnetNotificationParametersExtended) PeekedTagNumber() uint8 {
+	return uint8(9)
+}
 
-func (m *BACnetNotificationParametersExtended) InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) {
+func (m *BACnetNotificationParametersExtended) InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) {
 	m.OpeningTag = openingTag
-	m.PeekedTagNumber = peekedTagNumber
+	m.PeekedTagHeader = peekedTagHeader
 	m.ClosingTag = closingTag
 }
 
-func NewBACnetNotificationParametersExtended(innerOpeningTag *BACnetOpeningTag, vendorId *BACnetContextTagUnsignedInteger, extendedEventType *BACnetContextTagUnsignedInteger, parameters *BACnetNotificationParametersExtendedParameters, innerClosingTag *BACnetClosingTag, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetNotificationParameters {
+func NewBACnetNotificationParametersExtended(innerOpeningTag *BACnetOpeningTag, vendorId *BACnetContextTagUnsignedInteger, extendedEventType *BACnetContextTagUnsignedInteger, parameters *BACnetNotificationParametersExtendedParameters, innerClosingTag *BACnetClosingTag, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetNotificationParameters {
 	child := &BACnetNotificationParametersExtended{
 		InnerOpeningTag:              innerOpeningTag,
 		VendorId:                     vendorId,
 		ExtendedEventType:            extendedEventType,
 		Parameters:                   parameters,
 		InnerClosingTag:              innerClosingTag,
-		BACnetNotificationParameters: NewBACnetNotificationParameters(openingTag, peekedTagNumber, closingTag),
+		BACnetNotificationParameters: NewBACnetNotificationParameters(openingTag, peekedTagHeader, closingTag, peekedTagNumber),
 	}
 	child.Child = child
 	return child.BACnetNotificationParameters
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersUnsignedRange.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersUnsignedRange.go
index 44b5ffb..4334db5 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersUnsignedRange.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetNotificationParametersUnsignedRange.go
@@ -46,21 +46,24 @@ type IBACnetNotificationParametersUnsignedRange interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
+func (m *BACnetNotificationParametersUnsignedRange) PeekedTagNumber() uint8 {
+	return uint8(11)
+}
 
-func (m *BACnetNotificationParametersUnsignedRange) InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) {
+func (m *BACnetNotificationParametersUnsignedRange) InitializeParent(parent *BACnetNotificationParameters, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) {
 	m.OpeningTag = openingTag
-	m.PeekedTagNumber = peekedTagNumber
+	m.PeekedTagHeader = peekedTagHeader
 	m.ClosingTag = closingTag
 }
 
-func NewBACnetNotificationParametersUnsignedRange(innerOpeningTag *BACnetOpeningTag, sequenceNumber *BACnetContextTagUnsignedInteger, statusFlags *BACnetStatusFlags, exceededLimit *BACnetContextTagUnsignedInteger, innerClosingTag *BACnetClosingTag, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetNotificationParameters {
+func NewBACnetNotificationParametersUnsignedRange(innerOpeningTag *BACnetOpeningTag, sequenceNumber *BACnetContextTagUnsignedInteger, statusFlags *BACnetStatusFlags, exceededLimit *BACnetContextTagUnsignedInteger, innerClosingTag *BACnetClosingTag, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetNotificationParameters {
 	child := &BACnetNotificationParametersUnsignedRange{
 		InnerOpeningTag:              innerOpeningTag,
 		SequenceNumber:               sequenceNumber,
 		StatusFlags:                  statusFlags,
 		ExceededLimit:                exceededLimit,
 		InnerClosingTag:              innerClosingTag,
-		BACnetNotificationParameters: NewBACnetNotificationParameters(openingTag, peekedTagNumber, closingTag),
+		BACnetNotificationParameters: NewBACnetNotificationParameters(openingTag, peekedTagHeader, closingTag, peekedTagNumber),
 	}
 	child.Child = child
 	return child.BACnetNotificationParameters
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyStates.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyStates.go
index f08e87b..9264144 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyStates.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyStates.go
@@ -29,13 +29,15 @@ import (
 // The data-structure of this message
 type BACnetPropertyStates struct {
 	OpeningTag      *BACnetOpeningTag
-	PeekedTagNumber uint8
+	PeekedTagHeader *BACnetTagHeader
 	ClosingTag      *BACnetClosingTag
+	PeekedTagNumber uint8
 	Child           IBACnetPropertyStatesChild
 }
 
 // The corresponding interface
 type IBACnetPropertyStates interface {
+	PeekedTagNumber() uint8
 	LengthInBytes() uint16
 	LengthInBits() uint16
 	Serialize(writeBuffer utils.WriteBuffer) error
@@ -48,13 +50,13 @@ type IBACnetPropertyStatesParent interface {
 
 type IBACnetPropertyStatesChild interface {
 	Serialize(writeBuffer utils.WriteBuffer) error
-	InitializeParent(parent *BACnetPropertyStates, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag)
+	InitializeParent(parent *BACnetPropertyStates, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8)
 	GetTypeName() string
 	IBACnetPropertyStates
 }
 
-func NewBACnetPropertyStates(openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetPropertyStates {
-	return &BACnetPropertyStates{OpeningTag: openingTag, PeekedTagNumber: peekedTagNumber, ClosingTag: closingTag}
+func NewBACnetPropertyStates(openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetPropertyStates {
+	return &BACnetPropertyStates{OpeningTag: openingTag, PeekedTagHeader: peekedTagHeader, ClosingTag: closingTag, PeekedTagNumber: peekedTagNumber}
 }
 
 func CastBACnetPropertyStates(structType interface{}) *BACnetPropertyStates {
@@ -88,6 +90,8 @@ func (m *BACnetPropertyStates) ParentLengthInBits() uint16 {
 	// Simple field (openingTag)
 	lengthInBits += m.OpeningTag.LengthInBits()
 
+	// A virtual field doesn't have any in- or output.
+
 	// Simple field (closingTag)
 	lengthInBits += m.ClosingTag.LengthInBits()
 
@@ -116,14 +120,18 @@ func BACnetPropertyStatesParse(readBuffer utils.ReadBuffer, tagNumber uint8) (*B
 		return nil, closeErr
 	}
 
-	// Peek Field (peekedTagNumber)
+	// Peek Field (peekedTagHeader)
 	currentPos := readBuffer.GetPos()
-	peekedTagNumber, _err := readBuffer.ReadUint8("peekedTagNumber", 4)
-	if _err != nil {
-		return nil, errors.Wrap(_err, "Error parsing 'peekedTagNumber' field")
+	if pullErr := readBuffer.PullContext("peekedTagHeader"); pullErr != nil {
+		return nil, pullErr
 	}
+	peekedTagHeader, _ := BACnetTagHeaderParse(readBuffer)
 	readBuffer.Reset(currentPos)
 
+	// Virtual field
+	_peekedTagNumber := peekedTagHeader.ActualTagNumber
+	peekedTagNumber := uint8(_peekedTagNumber)
+
 	// Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
 	var _parent *BACnetPropertyStates
 	var typeSwitchError error
@@ -158,7 +166,7 @@ func BACnetPropertyStatesParse(readBuffer utils.ReadBuffer, tagNumber uint8) (*B
 	}
 
 	// Finish initializing
-	_parent.Child.InitializeParent(_parent, openingTag, peekedTagNumber, closingTag)
+	_parent.Child.InitializeParent(_parent, openingTag, peekedTagHeader, closingTag, peekedTagNumber)
 	return _parent, nil
 }
 
@@ -182,6 +190,10 @@ func (m *BACnetPropertyStates) SerializeParent(writeBuffer utils.WriteBuffer, ch
 	if _openingTagErr != nil {
 		return errors.Wrap(_openingTagErr, "Error serializing 'openingTag' field")
 	}
+	// Virtual field
+	if _peekedTagNumberErr := writeBuffer.WriteVirtual("peekedTagNumber", m.PeekedTagNumber); _peekedTagNumberErr != nil {
+		return errors.Wrap(_peekedTagNumberErr, "Error serializing 'peekedTagNumber' field")
+	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
 	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyStatesAction.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyStatesAction.go
index 619486b..aa4e29d 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyStatesAction.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyStatesAction.go
@@ -42,17 +42,20 @@ type IBACnetPropertyStatesAction interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
+func (m *BACnetPropertyStatesAction) PeekedTagNumber() uint8 {
+	return uint8(16)
+}
 
-func (m *BACnetPropertyStatesAction) InitializeParent(parent *BACnetPropertyStates, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) {
+func (m *BACnetPropertyStatesAction) InitializeParent(parent *BACnetPropertyStates, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) {
 	m.OpeningTag = openingTag
-	m.PeekedTagNumber = peekedTagNumber
+	m.PeekedTagHeader = peekedTagHeader
 	m.ClosingTag = closingTag
 }
 
-func NewBACnetPropertyStatesAction(action *BACnetAction, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetPropertyStates {
+func NewBACnetPropertyStatesAction(action *BACnetAction, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetPropertyStates {
 	child := &BACnetPropertyStatesAction{
 		Action:               action,
-		BACnetPropertyStates: NewBACnetPropertyStates(openingTag, peekedTagNumber, closingTag),
+		BACnetPropertyStates: NewBACnetPropertyStates(openingTag, peekedTagHeader, closingTag, peekedTagNumber),
 	}
 	child.Child = child
 	return child.BACnetPropertyStates
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyStatesBoolean.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyStatesBoolean.go
index 15ce381..feb1691 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyStatesBoolean.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetPropertyStatesBoolean.go
@@ -42,17 +42,20 @@ type IBACnetPropertyStatesBoolean interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
+func (m *BACnetPropertyStatesBoolean) PeekedTagNumber() uint8 {
+	return uint8(0)
+}
 
-func (m *BACnetPropertyStatesBoolean) InitializeParent(parent *BACnetPropertyStates, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) {
+func (m *BACnetPropertyStatesBoolean) InitializeParent(parent *BACnetPropertyStates, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) {
 	m.OpeningTag = openingTag
-	m.PeekedTagNumber = peekedTagNumber
+	m.PeekedTagHeader = peekedTagHeader
 	m.ClosingTag = closingTag
 }
 
-func NewBACnetPropertyStatesBoolean(booleanValue *BACnetContextTagBoolean, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetPropertyStates {
+func NewBACnetPropertyStatesBoolean(booleanValue *BACnetContextTagBoolean, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetPropertyStates {
 	child := &BACnetPropertyStatesBoolean{
 		BooleanValue:         booleanValue,
-		BACnetPropertyStates: NewBACnetPropertyStates(openingTag, peekedTagNumber, closingTag),
+		BACnetPropertyStates: NewBACnetPropertyStates(openingTag, peekedTagHeader, closingTag, peekedTagNumber),
 	}
 	child.Child = child
 	return child.BACnetPropertyStates
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagHeader.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagHeader.go
new file mode 100644
index 0000000..93aacea
--- /dev/null
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagHeader.go
@@ -0,0 +1,334 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package model
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils"
+	"github.com/pkg/errors"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// The data-structure of this message
+type BACnetTagHeader struct {
+	TagNumber                uint8
+	TagClass                 TagClass
+	LengthValueType          uint8
+	ExtTagNumber             *uint8
+	ExtLength                *uint8
+	ExtExtLength             *uint16
+	ExtExtExtLength          *uint32
+	ActualTagNumber          uint8
+	IsBoolean                bool
+	IsConstructed            bool
+	IsPrimitiveAndNotBoolean bool
+	ActualLength             uint32
+}
+
+// The corresponding interface
+type IBACnetTagHeader interface {
+	LengthInBytes() uint16
+	LengthInBits() uint16
+	Serialize(writeBuffer utils.WriteBuffer) error
+}
+
+func NewBACnetTagHeader(tagNumber uint8, tagClass TagClass, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, actualTagNumber uint8, isBoolean bool, isConstructed bool, isPrimitiveAndNotBoolean bool, actualLength uint32) *BACnetTagHeader {
+	return &BACnetTagHeader{TagNumber: tagNumber, TagClass: tagClass, LengthValueType: lengthValueType, ExtTagNumber: extTagNumber, ExtLength: extLength, ExtExtLength: extExtLength, ExtExtExtLength: extExtExtLength, ActualTagNumber: actualTagNumber, IsBoolean: isBoolean, IsConstructed: isConstructed, IsPrimitiveAndNotBoolean: isPrimitiveAndNotBoolean, ActualLength: actualLength}
+}
+
+func CastBACnetTagHeader(structType interface{}) *BACnetTagHeader {
+	castFunc := func(typ interface{}) *BACnetTagHeader {
+		if casted, ok := typ.(BACnetTagHeader); ok {
+			return &casted
+		}
+		if casted, ok := typ.(*BACnetTagHeader); ok {
+			return casted
+		}
+		return nil
+	}
+	return castFunc(structType)
+}
+
+func (m *BACnetTagHeader) GetTypeName() string {
+	return "BACnetTagHeader"
+}
+
+func (m *BACnetTagHeader) LengthInBits() uint16 {
+	return m.LengthInBitsConditional(false)
+}
+
+func (m *BACnetTagHeader) LengthInBitsConditional(lastItem bool) uint16 {
+	lengthInBits := uint16(0)
+
+	// Simple field (tagNumber)
+	lengthInBits += 4
+
+	// Simple field (tagClass)
+	lengthInBits += 1
+
+	// Simple field (lengthValueType)
+	lengthInBits += 3
+
+	// Optional Field (extTagNumber)
+	if m.ExtTagNumber != nil {
+		lengthInBits += 8
+	}
+
+	// A virtual field doesn't have any in- or output.
+
+	// A virtual field doesn't have any in- or output.
+
+	// A virtual field doesn't have any in- or output.
+
+	// A virtual field doesn't have any in- or output.
+
+	// Optional Field (extLength)
+	if m.ExtLength != nil {
+		lengthInBits += 8
+	}
+
+	// Optional Field (extExtLength)
+	if m.ExtExtLength != nil {
+		lengthInBits += 16
+	}
+
+	// Optional Field (extExtExtLength)
+	if m.ExtExtExtLength != nil {
+		lengthInBits += 32
+	}
+
+	// A virtual field doesn't have any in- or output.
+
+	return lengthInBits
+}
+
+func (m *BACnetTagHeader) LengthInBytes() uint16 {
+	return m.LengthInBits() / 8
+}
+
+func BACnetTagHeaderParse(readBuffer utils.ReadBuffer) (*BACnetTagHeader, error) {
+	if pullErr := readBuffer.PullContext("BACnetTagHeader"); pullErr != nil {
+		return nil, pullErr
+	}
+
+	// Simple Field (tagNumber)
+	_tagNumber, _tagNumberErr := readBuffer.ReadUint8("tagNumber", 4)
+	if _tagNumberErr != nil {
+		return nil, errors.Wrap(_tagNumberErr, "Error parsing 'tagNumber' field")
+	}
+	tagNumber := _tagNumber
+
+	// Simple Field (tagClass)
+	if pullErr := readBuffer.PullContext("tagClass"); pullErr != nil {
+		return nil, pullErr
+	}
+	_tagClass, _tagClassErr := TagClassParse(readBuffer)
+	if _tagClassErr != nil {
+		return nil, errors.Wrap(_tagClassErr, "Error parsing 'tagClass' field")
+	}
+	tagClass := _tagClass
+	if closeErr := readBuffer.CloseContext("tagClass"); closeErr != nil {
+		return nil, closeErr
+	}
+
+	// Simple Field (lengthValueType)
+	_lengthValueType, _lengthValueTypeErr := readBuffer.ReadUint8("lengthValueType", 3)
+	if _lengthValueTypeErr != nil {
+		return nil, errors.Wrap(_lengthValueTypeErr, "Error parsing 'lengthValueType' field")
+	}
+	lengthValueType := _lengthValueType
+
+	// Optional Field (extTagNumber) (Can be skipped, if a given expression evaluates to false)
+	var extTagNumber *uint8 = nil
+	if bool((tagNumber) == (15)) {
+		_val, _err := readBuffer.ReadUint8("extTagNumber", 8)
+		if _err != nil {
+			return nil, errors.Wrap(_err, "Error parsing 'extTagNumber' field")
+		}
+		extTagNumber = &_val
+	}
+
+	// Virtual field
+	_actualTagNumber := utils.InlineIf(bool((tagNumber) < (15)), func() interface{} { return uint8(tagNumber) }, func() interface{} { return uint8((*extTagNumber)) }).(uint8)
+	actualTagNumber := uint8(_actualTagNumber)
+
+	// Virtual field
+	_isBoolean := bool(bool((tagNumber) == (1))) && bool(bool((tagClass) == (TagClass_APPLICATION_TAGS)))
+	isBoolean := bool(_isBoolean)
+
+	// Virtual field
+	_isConstructed := bool(bool((tagClass) == (TagClass_CONTEXT_SPECIFIC_TAGS))) && bool(bool((lengthValueType) == (6)))
+	isConstructed := bool(_isConstructed)
+
+	// Virtual field
+	_isPrimitiveAndNotBoolean := bool(!(isConstructed)) && bool(!(isBoolean))
+	isPrimitiveAndNotBoolean := bool(_isPrimitiveAndNotBoolean)
+
+	// Optional Field (extLength) (Can be skipped, if a given expression evaluates to false)
+	var extLength *uint8 = nil
+	if bool(isPrimitiveAndNotBoolean) && bool(bool((lengthValueType) == (5))) {
+		_val, _err := readBuffer.ReadUint8("extLength", 8)
+		if _err != nil {
+			return nil, errors.Wrap(_err, "Error parsing 'extLength' field")
+		}
+		extLength = &_val
+	}
+
+	// Optional Field (extExtLength) (Can be skipped, if a given expression evaluates to false)
+	var extExtLength *uint16 = nil
+	if bool(bool(isPrimitiveAndNotBoolean) && bool(bool((lengthValueType) == (5)))) && bool(bool((*extLength) == (254))) {
+		_val, _err := readBuffer.ReadUint16("extExtLength", 16)
+		if _err != nil {
+			return nil, errors.Wrap(_err, "Error parsing 'extExtLength' field")
+		}
+		extExtLength = &_val
+	}
+
+	// Optional Field (extExtExtLength) (Can be skipped, if a given expression evaluates to false)
+	var extExtExtLength *uint32 = nil
+	if bool(bool(isPrimitiveAndNotBoolean) && bool(bool((lengthValueType) == (5)))) && bool(bool((*extLength) == (255))) {
+		_val, _err := readBuffer.ReadUint32("extExtExtLength", 32)
+		if _err != nil {
+			return nil, errors.Wrap(_err, "Error parsing 'extExtExtLength' field")
+		}
+		extExtExtLength = &_val
+	}
+
+	// Virtual field
+	_actualLength := utils.InlineIf(bool(bool((lengthValueType) == (5))) && bool(bool((*extLength) == (255))), func() interface{} { return uint32((*extExtExtLength)) }, func() interface{} {
+		return uint32(uint32(utils.InlineIf(bool(bool((lengthValueType) == (5))) && bool(bool((*extLength) == (254))), func() interface{} { return uint32((*extExtLength)) }, func() interface{} {
+			return uint32(uint32(utils.InlineIf(bool((lengthValueType) == (5)), func() interface{} { return uint32((*extLength)) }, func() interface{} { return uint32(lengthValueType) }).(uint32)))
+		}).(uint32)))
+	}).(uint32)
+	actualLength := uint32(_actualLength)
+
+	if closeErr := readBuffer.CloseContext("BACnetTagHeader"); closeErr != nil {
+		return nil, closeErr
+	}
+
+	// Create the instance
+	return NewBACnetTagHeader(tagNumber, tagClass, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength, actualTagNumber, isBoolean, isConstructed, isPrimitiveAndNotBoolean, actualLength), nil
+}
+
+func (m *BACnetTagHeader) Serialize(writeBuffer utils.WriteBuffer) error {
+	if pushErr := writeBuffer.PushContext("BACnetTagHeader"); pushErr != nil {
+		return pushErr
+	}
+
+	// Simple Field (tagNumber)
+	tagNumber := uint8(m.TagNumber)
+	_tagNumberErr := writeBuffer.WriteUint8("tagNumber", 4, (tagNumber))
+	if _tagNumberErr != nil {
+		return errors.Wrap(_tagNumberErr, "Error serializing 'tagNumber' field")
+	}
+
+	// Simple Field (tagClass)
+	if pushErr := writeBuffer.PushContext("tagClass"); pushErr != nil {
+		return pushErr
+	}
+	_tagClassErr := m.TagClass.Serialize(writeBuffer)
+	if popErr := writeBuffer.PopContext("tagClass"); popErr != nil {
+		return popErr
+	}
+	if _tagClassErr != nil {
+		return errors.Wrap(_tagClassErr, "Error serializing 'tagClass' field")
+	}
+
+	// Simple Field (lengthValueType)
+	lengthValueType := uint8(m.LengthValueType)
+	_lengthValueTypeErr := writeBuffer.WriteUint8("lengthValueType", 3, (lengthValueType))
+	if _lengthValueTypeErr != nil {
+		return errors.Wrap(_lengthValueTypeErr, "Error serializing 'lengthValueType' field")
+	}
+
+	// Optional Field (extTagNumber) (Can be skipped, if the value is null)
+	var extTagNumber *uint8 = nil
+	if m.ExtTagNumber != nil {
+		extTagNumber = m.ExtTagNumber
+		_extTagNumberErr := writeBuffer.WriteUint8("extTagNumber", 8, *(extTagNumber))
+		if _extTagNumberErr != nil {
+			return errors.Wrap(_extTagNumberErr, "Error serializing 'extTagNumber' field")
+		}
+	}
+	// Virtual field
+	if _actualTagNumberErr := writeBuffer.WriteVirtual("actualTagNumber", m.ActualTagNumber); _actualTagNumberErr != nil {
+		return errors.Wrap(_actualTagNumberErr, "Error serializing 'actualTagNumber' field")
+	}
+	// Virtual field
+	if _isBooleanErr := writeBuffer.WriteVirtual("isBoolean", m.IsBoolean); _isBooleanErr != nil {
+		return errors.Wrap(_isBooleanErr, "Error serializing 'isBoolean' field")
+	}
+	// Virtual field
+	if _isConstructedErr := writeBuffer.WriteVirtual("isConstructed", m.IsConstructed); _isConstructedErr != nil {
+		return errors.Wrap(_isConstructedErr, "Error serializing 'isConstructed' field")
+	}
+	// Virtual field
+	if _isPrimitiveAndNotBooleanErr := writeBuffer.WriteVirtual("isPrimitiveAndNotBoolean", m.IsPrimitiveAndNotBoolean); _isPrimitiveAndNotBooleanErr != nil {
+		return errors.Wrap(_isPrimitiveAndNotBooleanErr, "Error serializing 'isPrimitiveAndNotBoolean' field")
+	}
+
+	// Optional Field (extLength) (Can be skipped, if the value is null)
+	var extLength *uint8 = nil
+	if m.ExtLength != nil {
+		extLength = m.ExtLength
+		_extLengthErr := writeBuffer.WriteUint8("extLength", 8, *(extLength))
+		if _extLengthErr != nil {
+			return errors.Wrap(_extLengthErr, "Error serializing 'extLength' field")
+		}
+	}
+
+	// Optional Field (extExtLength) (Can be skipped, if the value is null)
+	var extExtLength *uint16 = nil
+	if m.ExtExtLength != nil {
+		extExtLength = m.ExtExtLength
+		_extExtLengthErr := writeBuffer.WriteUint16("extExtLength", 16, *(extExtLength))
+		if _extExtLengthErr != nil {
+			return errors.Wrap(_extExtLengthErr, "Error serializing 'extExtLength' field")
+		}
+	}
+
+	// Optional Field (extExtExtLength) (Can be skipped, if the value is null)
+	var extExtExtLength *uint32 = nil
+	if m.ExtExtExtLength != nil {
+		extExtExtLength = m.ExtExtExtLength
+		_extExtExtLengthErr := writeBuffer.WriteUint32("extExtExtLength", 32, *(extExtExtLength))
+		if _extExtExtLengthErr != nil {
+			return errors.Wrap(_extExtExtLengthErr, "Error serializing 'extExtExtLength' field")
+		}
+	}
+	// Virtual field
+	if _actualLengthErr := writeBuffer.WriteVirtual("actualLength", m.ActualLength); _actualLengthErr != nil {
+		return errors.Wrap(_actualLengthErr, "Error serializing 'actualLength' field")
+	}
+
+	if popErr := writeBuffer.PopContext("BACnetTagHeader"); popErr != nil {
+		return popErr
+	}
+	return nil
+}
+
+func (m *BACnetTagHeader) String() string {
+	if m == nil {
+		return "<nil>"
+	}
+	buffer := utils.NewBoxedWriteBufferWithOptions(true, true)
+	m.Serialize(buffer)
+	return buffer.GetBox().String()
+}
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStamp.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStamp.go
index ed451e0..43b46fd 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStamp.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStamp.go
@@ -29,13 +29,15 @@ import (
 // The data-structure of this message
 type BACnetTimeStamp struct {
 	OpeningTag      *BACnetOpeningTag
-	PeekedTagNumber uint8
+	PeekedTagHeader *BACnetTagHeader
 	ClosingTag      *BACnetClosingTag
+	PeekedTagNumber uint8
 	Child           IBACnetTimeStampChild
 }
 
 // The corresponding interface
 type IBACnetTimeStamp interface {
+	PeekedTagNumber() uint8
 	LengthInBytes() uint16
 	LengthInBits() uint16
 	Serialize(writeBuffer utils.WriteBuffer) error
@@ -48,13 +50,13 @@ type IBACnetTimeStampParent interface {
 
 type IBACnetTimeStampChild interface {
 	Serialize(writeBuffer utils.WriteBuffer) error
-	InitializeParent(parent *BACnetTimeStamp, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag)
+	InitializeParent(parent *BACnetTimeStamp, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8)
 	GetTypeName() string
 	IBACnetTimeStamp
 }
 
-func NewBACnetTimeStamp(openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetTimeStamp {
-	return &BACnetTimeStamp{OpeningTag: openingTag, PeekedTagNumber: peekedTagNumber, ClosingTag: closingTag}
+func NewBACnetTimeStamp(openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetTimeStamp {
+	return &BACnetTimeStamp{OpeningTag: openingTag, PeekedTagHeader: peekedTagHeader, ClosingTag: closingTag, PeekedTagNumber: peekedTagNumber}
 }
 
 func CastBACnetTimeStamp(structType interface{}) *BACnetTimeStamp {
@@ -88,6 +90,8 @@ func (m *BACnetTimeStamp) ParentLengthInBits() uint16 {
 	// Simple field (openingTag)
 	lengthInBits += m.OpeningTag.LengthInBits()
 
+	// A virtual field doesn't have any in- or output.
+
 	// Simple field (closingTag)
 	lengthInBits += m.ClosingTag.LengthInBits()
 
@@ -116,14 +120,18 @@ func BACnetTimeStampParse(readBuffer utils.ReadBuffer, tagNumber uint8) (*BACnet
 		return nil, closeErr
 	}
 
-	// Peek Field (peekedTagNumber)
+	// Peek Field (peekedTagHeader)
 	currentPos := readBuffer.GetPos()
-	peekedTagNumber, _err := readBuffer.ReadUint8("peekedTagNumber", 4)
-	if _err != nil {
-		return nil, errors.Wrap(_err, "Error parsing 'peekedTagNumber' field")
+	if pullErr := readBuffer.PullContext("peekedTagHeader"); pullErr != nil {
+		return nil, pullErr
 	}
+	peekedTagHeader, _ := BACnetTagHeaderParse(readBuffer)
 	readBuffer.Reset(currentPos)
 
+	// Virtual field
+	_peekedTagNumber := peekedTagHeader.ActualTagNumber
+	peekedTagNumber := uint8(_peekedTagNumber)
+
 	// Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
 	var _parent *BACnetTimeStamp
 	var typeSwitchError error
@@ -160,7 +168,7 @@ func BACnetTimeStampParse(readBuffer utils.ReadBuffer, tagNumber uint8) (*BACnet
 	}
 
 	// Finish initializing
-	_parent.Child.InitializeParent(_parent, openingTag, peekedTagNumber, closingTag)
+	_parent.Child.InitializeParent(_parent, openingTag, peekedTagHeader, closingTag, peekedTagNumber)
 	return _parent, nil
 }
 
@@ -184,6 +192,10 @@ func (m *BACnetTimeStamp) SerializeParent(writeBuffer utils.WriteBuffer, child I
 	if _openingTagErr != nil {
 		return errors.Wrap(_openingTagErr, "Error serializing 'openingTag' field")
 	}
+	// Virtual field
+	if _peekedTagNumberErr := writeBuffer.WriteVirtual("peekedTagNumber", m.PeekedTagNumber); _peekedTagNumberErr != nil {
+		return errors.Wrap(_peekedTagNumberErr, "Error serializing 'peekedTagNumber' field")
+	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
 	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStampDateTime.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStampDateTime.go
index f922f47..6f7d3e9 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStampDateTime.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStampDateTime.go
@@ -42,17 +42,20 @@ type IBACnetTimeStampDateTime interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
+func (m *BACnetTimeStampDateTime) PeekedTagNumber() uint8 {
+	return uint8(2)
+}
 
-func (m *BACnetTimeStampDateTime) InitializeParent(parent *BACnetTimeStamp, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) {
+func (m *BACnetTimeStampDateTime) InitializeParent(parent *BACnetTimeStamp, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) {
 	m.OpeningTag = openingTag
-	m.PeekedTagNumber = peekedTagNumber
+	m.PeekedTagHeader = peekedTagHeader
 	m.ClosingTag = closingTag
 }
 
-func NewBACnetTimeStampDateTime(dateTimeValue *BACnetDateTime, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetTimeStamp {
+func NewBACnetTimeStampDateTime(dateTimeValue *BACnetDateTime, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetTimeStamp {
 	child := &BACnetTimeStampDateTime{
 		DateTimeValue:   dateTimeValue,
-		BACnetTimeStamp: NewBACnetTimeStamp(openingTag, peekedTagNumber, closingTag),
+		BACnetTimeStamp: NewBACnetTimeStamp(openingTag, peekedTagHeader, closingTag, peekedTagNumber),
 	}
 	child.Child = child
 	return child.BACnetTimeStamp
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStampSequence.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStampSequence.go
index 541b05d..5e03d82 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStampSequence.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStampSequence.go
@@ -42,17 +42,20 @@ type IBACnetTimeStampSequence interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
+func (m *BACnetTimeStampSequence) PeekedTagNumber() uint8 {
+	return uint8(1)
+}
 
-func (m *BACnetTimeStampSequence) InitializeParent(parent *BACnetTimeStamp, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) {
+func (m *BACnetTimeStampSequence) InitializeParent(parent *BACnetTimeStamp, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) {
 	m.OpeningTag = openingTag
-	m.PeekedTagNumber = peekedTagNumber
+	m.PeekedTagHeader = peekedTagHeader
 	m.ClosingTag = closingTag
 }
 
-func NewBACnetTimeStampSequence(sequenceNumber *BACnetContextTagUnsignedInteger, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetTimeStamp {
+func NewBACnetTimeStampSequence(sequenceNumber *BACnetContextTagUnsignedInteger, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetTimeStamp {
 	child := &BACnetTimeStampSequence{
 		SequenceNumber:  sequenceNumber,
-		BACnetTimeStamp: NewBACnetTimeStamp(openingTag, peekedTagNumber, closingTag),
+		BACnetTimeStamp: NewBACnetTimeStamp(openingTag, peekedTagHeader, closingTag, peekedTagNumber),
 	}
 	child.Child = child
 	return child.BACnetTimeStamp
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStampTime.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStampTime.go
index 64a7be5..5edec3f 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStampTime.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTimeStampTime.go
@@ -42,17 +42,20 @@ type IBACnetTimeStampTime interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
+func (m *BACnetTimeStampTime) PeekedTagNumber() uint8 {
+	return uint8(0)
+}
 
-func (m *BACnetTimeStampTime) InitializeParent(parent *BACnetTimeStamp, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) {
+func (m *BACnetTimeStampTime) InitializeParent(parent *BACnetTimeStamp, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) {
 	m.OpeningTag = openingTag
-	m.PeekedTagNumber = peekedTagNumber
+	m.PeekedTagHeader = peekedTagHeader
 	m.ClosingTag = closingTag
 }
 
-func NewBACnetTimeStampTime(timeValue *BACnetContextTagTime, openingTag *BACnetOpeningTag, peekedTagNumber uint8, closingTag *BACnetClosingTag) *BACnetTimeStamp {
+func NewBACnetTimeStampTime(timeValue *BACnetContextTagTime, openingTag *BACnetOpeningTag, peekedTagHeader *BACnetTagHeader, closingTag *BACnetClosingTag, peekedTagNumber uint8) *BACnetTimeStamp {
 	child := &BACnetTimeStampTime{
 		TimeValue:       timeValue,
-		BACnetTimeStamp: NewBACnetTimeStamp(openingTag, peekedTagNumber, closingTag),
+		BACnetTimeStamp: NewBACnetTimeStamp(openingTag, peekedTagHeader, closingTag, peekedTagNumber),
 	}
 	child.Child = child
 	return child.BACnetTimeStamp
diff --git a/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/RandomPackagesTest.java b/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/RandomPackagesTest.java
index 37b9734..8e1a1d6 100644
--- a/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/RandomPackagesTest.java
+++ b/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/RandomPackagesTest.java
@@ -1004,7 +1004,6 @@ public class RandomPackagesTest {
         })).map(DynamicNode.class::cast).iterator());
     }
 
-    @Disabled("not working because of tag numbers > 15")
     @TestFactory
     @DisplayName("ContextTagAbove14Sample_1")
     Collection<DynamicNode> ContextTagAbove14Sample_1() throws Exception {
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderOptional.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderOptional.java
index 87ed2a1..f3a372e 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderOptional.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderOptional.java
@@ -46,6 +46,10 @@ public class FieldReaderOptional<T> implements FieldCommons {
             LOGGER.debug("Assertion doesn't match for field {}. Resetting read position to {}", logicalName, curPos, e);
             dataReader.setPos(curPos);
             return null;
+        } catch (ArrayIndexOutOfBoundsException e) {
+            LOGGER.debug("Not enough bytes for {}. Resetting read position to {}", logicalName, curPos, e);
+            dataReader.setPos(curPos);
+            return null;
         }
     }
 }
diff --git a/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec b/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
index 1712a48..6db5db3 100644
--- a/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
+++ b/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
@@ -491,13 +491,16 @@
     ]
 ]
 
-[type BACnetNotificationParameters(uint 4 tagNumber)
+[type BACnetNotificationParameters(uint 8 tagNumber)
     [simple     BACnetOpeningTag('tagNumber', 'BACnetDataType.OPENING_TAG')
-                openingTag
+                            openingTag
+    ]
+    [peek       BACnetTagHeader
+                            peekedTagHeader
     ]
-    [peek    uint 4  peekedTagNumber]
+    [virtual    uint 8      peekedTagNumber     'peekedTagHeader.actualTagNumber']
     [typeSwitch peekedTagNumber
-        ['0' BACnetNotificationParametersChangeOfBitString(uint 4 peekedTagNumber)
+        ['0' BACnetNotificationParametersChangeOfBitString(uint 8 peekedTagNumber)
             [simple BACnetOpeningTag('peekedTagNumber', 'BACnetDataType.OPENING_TAG')
                     innerOpeningTag
             ]
@@ -511,7 +514,7 @@
                     innerClosingTag
             ]
         ]
-        ['1' BACnetNotificationParametersChangeOfState(uint 4 peekedTagNumber)
+        ['1' BACnetNotificationParametersChangeOfState(uint 8 peekedTagNumber)
             [simple BACnetOpeningTag('peekedTagNumber', 'BACnetDataType.OPENING_TAG')
                     innerOpeningTag
             ]
@@ -525,7 +528,7 @@
                     innerClosingTag
             ]
         ]
-        ['2' BACnetNotificationParametersChangeOfValue(uint 4 peekedTagNumber)
+        ['2' BACnetNotificationParametersChangeOfValue(uint 8 peekedTagNumber)
             [simple BACnetOpeningTag('peekedTagNumber', 'BACnetDataType.OPENING_TAG')
                     innerOpeningTag
             ]
@@ -540,13 +543,13 @@
             ]
         ]
         // TODO: implement other cases
-        ['6' BACnetNotificationParametersComplexEventType(uint 4 peekedTagNumber)
+        ['6' BACnetNotificationParametersComplexEventType(uint 8 peekedTagNumber)
             [simple     BACnetPropertyValues('peekedTagNumber')
                         listOfValues
             ]
         ]
         // TODO: implement other cases
-        ['9' BACnetNotificationParametersExtended(uint 4 peekedTagNumber)
+        ['9' BACnetNotificationParametersExtended(uint 8 peekedTagNumber)
             [simple BACnetOpeningTag('peekedTagNumber', 'BACnetDataType.OPENING_TAG')
                     innerOpeningTag
             ]
@@ -563,7 +566,7 @@
                     innerClosingTag
             ]
         ]
-        ['10' BACnetNotificationParametersBufferReady(uint 4 peekedTagNumber)
+        ['10' BACnetNotificationParametersBufferReady(uint 8 peekedTagNumber)
             [simple BACnetOpeningTag('peekedTagNumber', 'BACnetDataType.OPENING_TAG')
                     innerOpeningTag
             ]
@@ -580,7 +583,7 @@
                     innerClosingTag
             ]
         ]
-        ['11' BACnetNotificationParametersUnsignedRange(uint 4 peekedTagNumber)
+        ['11' BACnetNotificationParametersUnsignedRange(uint 8 peekedTagNumber)
             [simple BACnetOpeningTag('peekedTagNumber', 'BACnetDataType.OPENING_TAG')
                     innerOpeningTag
             ]
@@ -605,18 +608,21 @@
 ]
 
 // TODO: this could be inlined once we can support nested types
-[type BACnetNotificationParametersChangeOfValueNewValue(uint 4 tagNumber)
+[type BACnetNotificationParametersChangeOfValueNewValue(uint 8 tagNumber)
     [simple     BACnetOpeningTag('tagNumber', 'BACnetDataType.OPENING_TAG')
                 openingTag
     ]
-    [peek       uint 4  peekedTagNumber]
+    [peek       BACnetTagHeader
+                            peekedTagHeader
+    ]
+    [virtual    uint 8      peekedTagNumber     'peekedTagHeader.actualTagNumber']
     [typeSwitch peekedTagNumber
-        ['0' BACnetNotificationParametersChangeOfValueNewValueChangedBits(uint 4 peekedTagNumber)
+        ['0' BACnetNotificationParametersChangeOfValueNewValueChangedBits(uint 8 peekedTagNumber)
             [simple BACnetContextTagBitString('0', 'BACnetDataType.BIT_STRING')
                     changedBits
             ]
         ]
-        ['1' BACnetNotificationParametersChangeOfValueNewValueChangedValue(uint 4 peekedTagNumber)
+        ['1' BACnetNotificationParametersChangeOfValueNewValueChangedValue(uint 8 peekedTagNumber)
             [simple BACnetContextTagReal('0', 'BACnetDataType.REAL')
                     changedValue
             ]
@@ -628,7 +634,7 @@
 ]
 
 // TODO: this could be inlined once we can support nested types
-[type BACnetNotificationParametersExtendedParameters(uint 4 tagNumber)
+[type BACnetNotificationParametersExtendedParameters(uint 8 tagNumber)
     [simple     BACnetOpeningTag('tagNumber', 'BACnetDataType.OPENING_TAG')
                 openingTag
     ]
@@ -665,7 +671,7 @@
     ]
 ]
 
-[type BACnetPropertyValues(uint 4 tagNumber)
+[type BACnetPropertyValues(uint 8 tagNumber)
     [simple BACnetOpeningTag('tagNumber', 'BACnetDataType.OPENING_TAG')
             innerOpeningTag
     ]
@@ -686,7 +692,7 @@
     [optional BACnetContextTagUnsignedInteger('3', 'BACnetDataType.UNSIGNED_INTEGER')              priority            ]
 ]
 
-[type BACnetDeviceObjectPropertyReference(uint 4 tagNumber)
+[type BACnetDeviceObjectPropertyReference(uint 8 tagNumber)
     [simple   BACnetOpeningTag('tagNumber', 'BACnetDataType.OPENING_TAG')
               openingTag
     ]
@@ -699,7 +705,7 @@
     ]
 ]
 
-[type BACnetStatusFlags(uint 4 tagNumber)
+[type BACnetStatusFlags(uint 8 tagNumber)
     [simple BACnetContextTagBitString('tagNumber', 'BACnetDataType.BIT_STRING')
         rawBits
     ]
@@ -709,28 +715,30 @@
     [virtual    bit outOfService    'rawBits.data[3]']
 ]
 
-[type BACnetAction(uint 4 tagNumber)
+[type BACnetAction(uint 8 tagNumber)
     [optional   BACnetContextTagEnumerated('tagNumber', 'BACnetDataType.ENUMERATED')
                 rawData
     ]
-    [virtual    bit isDirect         'rawData.data[0] == 0']
-    [virtual    bit isReverse        'rawData.data[1] == 1']
+    [virtual    bit isDirect         'rawData != null && COUNT(rawData.data) == 1 && rawData.data[0] == 0']
+    [virtual    bit isReverse        'rawData != null && COUNT(rawData.data) == 1 && rawData.data[0] == 1']
 ]
 
-[type BACnetPropertyStates(uint 4 tagNumber)
+[type BACnetPropertyStates(uint 8 tagNumber)
     [simple     BACnetOpeningTag('tagNumber', 'BACnetDataType.OPENING_TAG')
                 openingTag
     ]
-    //TODO: implement tag numbers >15
-    [peek       uint 4  peekedTagNumber]
+    [peek       BACnetTagHeader
+                            peekedTagHeader
+    ]
+    [virtual    uint 8      peekedTagNumber     'peekedTagHeader.actualTagNumber']
     [typeSwitch peekedTagNumber
-        ['0' BACnetPropertyStatesBoolean(uint 4 peekedTagNumber)
+        ['0' BACnetPropertyStatesBoolean(uint 8 peekedTagNumber)
             [optional   BACnetContextTagBoolean('peekedTagNumber', 'BACnetDataType.BOOLEAN')
                         booleanValue
             ]
         ]
         // TODO: add missing type
-        ['16' BACnetPropertyStatesAction(uint 4 peekedTagNumber)
+        ['16' BACnetPropertyStatesAction(uint 8 peekedTagNumber)
             [optional   BACnetAction('peekedTagNumber')
                         action
             ]
@@ -742,11 +750,14 @@
     ]
 ]
 
-[type BACnetTimeStamp(uint 4 tagNumber)
+[type BACnetTimeStamp(uint 8 tagNumber)
     [simple         BACnetOpeningTag('tagNumber', 'BACnetDataType.OPENING_TAG')
                     openingTag
     ]
-    [peek       uint 4  peekedTagNumber]
+    [peek       BACnetTagHeader
+                            peekedTagHeader
+    ]
+    [virtual    uint 8      peekedTagNumber     'peekedTagHeader.actualTagNumber']
     [typeSwitch peekedTagNumber
         ['0' BACnetTimeStampTime
             [simple BACnetContextTagTime('0', 'BACnetDataType.TIME')
@@ -769,7 +780,7 @@
     ]
 ]
 
-[type BACnetDateTime(uint 4 tagNumber)
+[type BACnetDateTime(uint 8 tagNumber)
     [simple     BACnetOpeningTag('tagNumber', 'BACnetDataType.OPENING_TAG')
                 openingTag
     ]
@@ -789,6 +800,21 @@
     [simple uint 16 port]
 ]
 
+[discriminatedType BACnetTagHeader
+    [simple        uint 4  tagNumber                                                                                  ]
+    [simple        TagClass tagClass                                                                                  ]
+    [simple        uint 3   lengthValueType                                                                           ]
+    [optional      uint 8   extTagNumber    'tagNumber == 15'                                                         ]
+    [virtual       uint 8   actualTagNumber 'tagNumber < 15 ? tagNumber : extTagNumber'                               ]
+    [virtual       bit      isBoolean       'tagNumber == 1 && tagClass == TagClass.APPLICATION_TAGS'                 ]
+    [virtual       bit      isConstructed   'tagClass == TagClass.CONTEXT_SPECIFIC_TAGS && lengthValueType == 6'      ]
+    [virtual       bit      isPrimitiveAndNotBoolean '!isConstructed && !isBoolean'                                   ]
+    [optional      uint 8   extLength       'isPrimitiveAndNotBoolean && lengthValueType == 5'                        ]
+    [optional      uint 16  extExtLength    'isPrimitiveAndNotBoolean && lengthValueType == 5 && extLength == 254'    ]
+    [optional      uint 32  extExtExtLength 'isPrimitiveAndNotBoolean && lengthValueType == 5 && extLength == 255'    ]
+    [virtual       uint 32  actualLength    'lengthValueType == 5 && extLength == 255 ? extExtExtLength : (lengthValueType == 5 && extLength == 254 ? extExtLength : (lengthValueType == 5 ? extLength : lengthValueType))']
+]
+
 [discriminatedType BACnetApplicationTag
     [discriminator uint 4   tagNumber                                                                                 ]
     [assert        TagClass tagClass        'TagClass.APPLICATION_TAGS'                                               ]
@@ -905,8 +931,8 @@
     ]
 ]
 
-[discriminatedType BACnetContextTag(uint 4 tagNumberArgument, BACnetDataType dataType)
-    [assert        uint 4           tagNumber           'tagNumberArgument'                                           ]
+[discriminatedType BACnetContextTag(uint 8 tagNumberArgument, BACnetDataType dataType)
+    [simple        uint 4           tagNumber                                                                         ]
     [assert        TagClass         tagClass            'TagClass.CONTEXT_SPECIFIC_TAGS'                              ]
     [simple        uint 3           lengthValueType                                                                   ]
     [optional      uint 8           extTagNumber        'tagNumber == 15'                                             ]
@@ -915,6 +941,7 @@
     [optional      uint 16          extExtLength        'lengthValueType == 5 && extLength == 254'                    ]
     [optional      uint 32          extExtExtLength     'lengthValueType == 5 && extLength == 255'                    ]
     [virtual       uint 32          actualLength        'lengthValueType == 5 && extLength == 255 ? extExtExtLength : (lengthValueType == 5 && extLength == 254 ? extExtLength : (lengthValueType == 5 ? extLength : lengthValueType))']
+    [validation                                         'actualTagNumber == tagNumberArgument'    "tagnumber doesn't match" ]
     [typeSwitch dataType, lengthValueType
         ['BOOLEAN' BACnetContextTagBoolean
             [simple  uint 8 value                          ]
@@ -979,9 +1006,7 @@
             [array      bit         unused count 'unusedBits'                            ]
         ]
         ['ENUMERATED' BACnetContextTagEnumerated(uint 32 actualLength)
-            // TODO: The reader expects int but uint32 gets mapped to long so even uint32 would easily overflow...
-            [virtual    uint 16     actualLengthInBit 'actualLength * 8']
-            [array       int 8      data length 'actualLengthInBit']
+            [array int 8 data length 'actualLength']
         ]
         ['DATE' BACnetContextTagDate
             [virtual int  8 wildcard '0xFF'                                 ]
@@ -1046,7 +1071,7 @@
     ]
 ]
 
-[type BACnetConstructedData(uint 4 tagNumber)
+[type BACnetConstructedData(uint 8 tagNumber)
     [optional       BACnetOpeningTag('tagNumber', 'BACnetDataType.OPENING_TAG')
                     openingTag
     ]
@@ -1069,16 +1094,18 @@
 ]
 
 [type BACnetConstructedDataElement
-    [peek       byte   peekedByte                                                                          ]
-    // TODO: maybe peek bits with a offset
-    [virtual    bit    isApplicationTag    'STATIC_CALL("isApplicationTag", peekedByte)'                   ]
-    [virtual    bit    isConstructedData   'STATIC_CALL("isConstructedData", peekedByte)'                  ]
-    [virtual    bit    isContextTag        '!isConstructedData && STATIC_CALL("isContextTag", peekedByte)' ]
+    [peek       BACnetTagHeader
+                            peekedTagHeader
+    ]
+    [virtual    uint 8      peekedTagNumber     'peekedTagHeader.actualTagNumber']
+    [virtual    bit    isApplicationTag    'peekedTagHeader.tagClass == TagClass.APPLICATION_TAGS'         ]
+    [virtual    bit    isConstructedData   '!isApplicationTag && peekedTagHeader.actualLength == 0x6'      ]
+    [virtual    bit    isContextTag        '!isConstructedData && !isApplicationTag'                       ]
     [optional   BACnetApplicationTag
                        applicationTag      'isApplicationTag'                                              ]
-    [optional   BACnetContextTag('(peekedByte & 0xF0) >> 4', 'STATIC_CALL("guessDataType")')
+    [optional   BACnetContextTag('peekedTagNumber', 'STATIC_CALL("guessDataType")')
                        contextTag          'isContextTag'                                                  ]
-    [optional   BACnetConstructedData('(peekedByte & 0xF0) >> 4')
+    [optional   BACnetConstructedData('peekedTagNumber')
                        constructedData     'isConstructedData'                                             ]
 ]