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 2021/09/17 18:40:49 UTC

[plc4x] 08/08: feat(pl4x): Reworked a bit of bacnet integration

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 6146cd1dff8f8334c77ef3f10575463951fce5d5
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Fri Sep 17 20:39:40 2021 +0200

    feat(pl4x): Reworked a bit of bacnet integration
    
    + slight reformatting of types
    + align names slightly to spec
    + convert uint 1 contextSpecificTag to a proper enum TagClass
    + added optional fields for lengths, for easy access the length can be accessed by using actual length
---
 .../drivers/tests/manual_bacnet_PcapTest_test.go   |  99 +++++++++++++
 plc4go/internal/plc4go/bacnetip/Connection.go      |   6 +-
 .../readwrite/model/APDUConfirmedRequest.go        |   2 +-
 .../plc4go/bacnetip/readwrite/model/BACnetTag.go   | 165 +++++++++++++++------
 .../model/BACnetTagApplicationBitString.go         |  16 +-
 .../readwrite/model/BACnetTagApplicationBoolean.go |  14 +-
 .../model/BACnetTagApplicationCharacterString.go   |  14 +-
 .../readwrite/model/BACnetTagApplicationDate.go    |  14 +-
 .../readwrite/model/BACnetTagApplicationDouble.go  |  14 +-
 .../model/BACnetTagApplicationEnumerated.go        |  16 +-
 .../readwrite/model/BACnetTagApplicationNull.go    |  14 +-
 .../model/BACnetTagApplicationObjectIdentifier.go  |  14 +-
 .../model/BACnetTagApplicationOctetString.go       |  14 +-
 .../readwrite/model/BACnetTagApplicationReal.go    |  14 +-
 .../model/BACnetTagApplicationSignedInteger.go     |  16 +-
 .../readwrite/model/BACnetTagApplicationTime.go    |  14 +-
 .../model/BACnetTagApplicationUnsignedInteger.go   |  16 +-
 .../bacnetip/readwrite/model/BACnetTagContext.go   |  18 ++-
 .../readwrite/model/BACnetTagWithContent.go        |  65 ++++----
 .../readwrite/model/NLMIAmRouterToNetwork.go       |   2 +-
 .../readwrite/model/NLMWhoIsRouterToNetwork.go     |   2 +-
 .../plc4go/bacnetip/readwrite/model/NPDU.go        |  12 +-
 .../plc4go/bacnetip/readwrite/model/TagClass.go    | 112 ++++++++++++++
 plc4go/internal/plc4go/spi/default/DefaultCodec.go |   2 +-
 .../resources/protocols/bacnetip/bacnetip.mspec    |  88 ++++++-----
 .../bacnetip/protocol/BacNetIpProtocolLogic.java   |  12 +-
 .../bacnetip/PassiveBacNetIpDriver2Manual.java     |  53 +++++++
 27 files changed, 604 insertions(+), 224 deletions(-)

diff --git a/plc4go/cmd/main/drivers/tests/manual_bacnet_PcapTest_test.go b/plc4go/cmd/main/drivers/tests/manual_bacnet_PcapTest_test.go
new file mode 100644
index 0000000..ea64b17
--- /dev/null
+++ b/plc4go/cmd/main/drivers/tests/manual_bacnet_PcapTest_test.go
@@ -0,0 +1,99 @@
+/*
+ * 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 tests
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/plc4go/bacnetip"
+	"github.com/apache/plc4x/plc4go/internal/plc4go/spi"
+	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/transports/pcap"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+	"github.com/rs/zerolog/log"
+	"io"
+	"net/http"
+	"os"
+	"path"
+	"testing"
+)
+
+func Test(t *testing.T) {
+	t.Skip() // Manual test don't check in un-skipped
+	file := path.Join(os.TempDir(), "bacnet-stack-services.cap")
+	_, err := os.Stat(file)
+	if os.IsNotExist(err) {
+		println("File does not exist... re-downloading")
+		if err := download(file, "https://wiki.wireshark.org/Protocols/bacnet?action=AttachFile&do=get&target=bacnet-stack-services.cap"); err != nil {
+			panic(err)
+		}
+	}
+	driverManager := plc4go.NewPlcDriverManager()
+	driverManager.RegisterDriver(bacnetip.NewDriver())
+	driverManager.(spi.TransportAware).RegisterTransport(pcap.NewTransport())
+	result := <-driverManager.GetConnection("bacnet-ip:pcap://" + file + "?transport-type=udp")
+	if result.Err != nil {
+		panic(result.Err)
+	}
+	connection := result.Connection
+	defer connection.Close()
+	build, err := connection.SubscriptionRequestBuilder().
+		AddEventQuery("furz", "*/*/*").
+		AddItemHandler(func(event model.PlcSubscriptionEvent) {
+			println(event)
+		}).
+		Build()
+	if err != nil {
+		panic(err)
+	}
+	requestResult := <-build.Execute()
+	if requestResult.Err != nil {
+		panic(requestResult.Err)
+	}
+	log.Info().Msgf("got response %v", requestResult.Response)
+
+	//time.Sleep(time.Hour)
+}
+
+func download(dstPath string, url string) error {
+	resp, err := http.Get(url)
+	if err != nil {
+		return err
+	}
+	defer func(Body io.ReadCloser) {
+		err := Body.Close()
+		if err != nil {
+			panic(err)
+		}
+	}(resp.Body)
+
+	// Create the file
+	out, err := os.Create(dstPath)
+	if err != nil {
+		return err
+	}
+	defer func(out *os.File) {
+		err := out.Close()
+		if err != nil {
+			panic(err)
+		}
+	}(out)
+
+	_, err = io.Copy(out, resp.Body)
+	return err
+}
diff --git a/plc4go/internal/plc4go/bacnetip/Connection.go b/plc4go/internal/plc4go/bacnetip/Connection.go
index 0b291bb..33434ee 100644
--- a/plc4go/internal/plc4go/bacnetip/Connection.go
+++ b/plc4go/internal/plc4go/bacnetip/Connection.go
@@ -62,14 +62,14 @@ func (c *Connection) UnsubscriptionRequestBuilder() model.PlcUnsubscriptionReque
 	panic("Not implementec yet. (at least as a default)")
 }
 
-func (m *Connection) addSubscriber(subscriber *Subscriber) {
-	for _, sub := range m.subscribers {
+func (c *Connection) addSubscriber(subscriber *Subscriber) {
+	for _, sub := range c.subscribers {
 		if sub == subscriber {
 			log.Debug().Msgf("Subscriber %v already added", subscriber)
 			return
 		}
 	}
-	m.subscribers = append(m.subscribers, subscriber)
+	c.subscribers = append(c.subscribers, subscriber)
 }
 
 func (c *Connection) String() string {
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/APDUConfirmedRequest.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/APDUConfirmedRequest.go
index 2e67ff9..7d1cd87 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/APDUConfirmedRequest.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/APDUConfirmedRequest.go
@@ -225,7 +225,7 @@ func APDUConfirmedRequestParse(readBuffer utils.ReadBuffer, apduLength uint16) (
 	if pullErr := readBuffer.PullContext("serviceRequest"); pullErr != nil {
 		return nil, pullErr
 	}
-	serviceRequest, _serviceRequestErr := BACnetConfirmedServiceRequestParse(readBuffer, uint16(apduLength)-uint16(uint16(uint16(uint16(3))+uint16(uint16(utils.InlineIf(segmentedMessage, func() uint16 { return uint16(uint16(2)) }, func() uint16 { return uint16(uint16(0)) }))))))
+	serviceRequest, _serviceRequestErr := BACnetConfirmedServiceRequestParse(readBuffer, uint16(apduLength)-uint16(uint16(uint16(uint16(3))+uint16(uint16(utils.InlineIf(segmentedMessage, func() interface{} { return uint16(uint16(2)) }, func() interface{} { return uint16(uint16(0)) }).(uint16))))))
 	if _serviceRequestErr != nil {
 		return nil, errors.Wrap(_serviceRequestErr, "Error parsing 'serviceRequest' field")
 	}
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTag.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTag.go
index 0639882..500de0d 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTag.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTag.go
@@ -28,16 +28,20 @@ import (
 
 // The data-structure of this message
 type BACnetTag struct {
-	TypeOrTagNumber uint8
-	LengthValueType uint8
-	ExtTagNumber    *uint8
-	ExtLength       *uint8
-	Child           IBACnetTagChild
+	TagNumber                uint8
+	LengthValueType          uint8
+	ExtTagNumber             *uint8
+	ExtLength                *uint8
+	ExtExtLength             *uint16
+	ExtExtExtLength          *uint32
+	IsPrimitiveAndNotBoolean bool
+	ActualLength             uint32
+	Child                    IBACnetTagChild
 }
 
 // The corresponding interface
 type IBACnetTag interface {
-	ContextSpecificTag() uint8
+	TagClass() TagClass
 	LengthInBytes() uint16
 	LengthInBits() uint16
 	Serialize(writeBuffer utils.WriteBuffer) error
@@ -50,13 +54,13 @@ type IBACnetTagParent interface {
 
 type IBACnetTagChild interface {
 	Serialize(writeBuffer utils.WriteBuffer) error
-	InitializeParent(parent *BACnetTag, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8)
+	InitializeParent(parent *BACnetTag, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, isPrimitiveAndNotBoolean bool, actualLength uint32)
 	GetTypeName() string
 	IBACnetTag
 }
 
-func NewBACnetTag(typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) *BACnetTag {
-	return &BACnetTag{TypeOrTagNumber: typeOrTagNumber, LengthValueType: lengthValueType, ExtTagNumber: extTagNumber, ExtLength: extLength}
+func NewBACnetTag(tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32) *BACnetTag {
+	return &BACnetTag{TagNumber: tagNumber, LengthValueType: lengthValueType, ExtTagNumber: extTagNumber, ExtLength: extLength, ExtExtLength: extExtLength, ExtExtExtLength: extExtExtLength}
 }
 
 func CastBACnetTag(structType interface{}) *BACnetTag {
@@ -87,14 +91,16 @@ func (m *BACnetTag) LengthInBitsConditional(lastItem bool) uint16 {
 func (m *BACnetTag) ParentLengthInBits() uint16 {
 	lengthInBits := uint16(0)
 
-	// Simple field (typeOrTagNumber)
+	// Simple field (tagNumber)
 	lengthInBits += 4
-	// Discriminator Field (contextSpecificTag)
+	// Discriminator Field (tagClass)
 	lengthInBits += 1
 
 	// Simple field (lengthValueType)
 	lengthInBits += 3
 
+	// A virtual field doesn't have any in- or output.
+
 	// Optional Field (extTagNumber)
 	if m.ExtTagNumber != nil {
 		lengthInBits += 8
@@ -105,6 +111,18 @@ func (m *BACnetTag) ParentLengthInBits() uint16 {
 		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
 }
 
@@ -117,16 +135,17 @@ func BACnetTagParse(readBuffer utils.ReadBuffer) (*BACnetTag, error) {
 		return nil, pullErr
 	}
 
-	// Simple Field (typeOrTagNumber)
-	typeOrTagNumber, _typeOrTagNumberErr := readBuffer.ReadUint8("typeOrTagNumber", 4)
-	if _typeOrTagNumberErr != nil {
-		return nil, errors.Wrap(_typeOrTagNumberErr, "Error parsing 'typeOrTagNumber' field")
+	// Simple Field (tagNumber)
+	tagNumber, _tagNumberErr := readBuffer.ReadUint8("tagNumber", 4)
+	if _tagNumberErr != nil {
+		return nil, errors.Wrap(_tagNumberErr, "Error parsing 'tagNumber' field")
 	}
 
-	// Discriminator Field (contextSpecificTag) (Used as input to a switch field)
-	contextSpecificTag, _contextSpecificTagErr := readBuffer.ReadUint8("contextSpecificTag", 1)
-	if _contextSpecificTagErr != nil {
-		return nil, errors.Wrap(_contextSpecificTagErr, "Error parsing 'contextSpecificTag' field")
+	// Discriminator Field (tagClass) (Used as input to a switch field)
+	tagClass_temp, _tagClassErr := TagClassParse(readBuffer)
+	var tagClass TagClass = tagClass_temp
+	if _tagClassErr != nil {
+		return nil, errors.Wrap(_tagClassErr, "Error parsing 'tagClass' field")
 	}
 
 	// Simple Field (lengthValueType)
@@ -135,9 +154,12 @@ func BACnetTagParse(readBuffer utils.ReadBuffer) (*BACnetTag, error) {
 		return nil, errors.Wrap(_lengthValueTypeErr, "Error parsing 'lengthValueType' field")
 	}
 
+	// Virtual field
+	isPrimitiveAndNotBoolean := bool(!(bool(bool(bool((tagClass) == (TagClass_CONTEXT_SPECIFIC_TAGS))) && bool(bool((lengthValueType) == (6)))))) && bool(bool((tagNumber) != (1)))
+
 	// Optional Field (extTagNumber) (Can be skipped, if a given expression evaluates to false)
 	var extTagNumber *uint8 = nil
-	if bool((typeOrTagNumber) == (15)) {
+	if bool(isPrimitiveAndNotBoolean) && bool(bool((tagNumber) == (15))) {
 		_val, _err := readBuffer.ReadUint8("extTagNumber", 8)
 		if _err != nil {
 			return nil, errors.Wrap(_err, "Error parsing 'extTagNumber' field")
@@ -147,7 +169,7 @@ func BACnetTagParse(readBuffer utils.ReadBuffer) (*BACnetTag, error) {
 
 	// Optional Field (extLength) (Can be skipped, if a given expression evaluates to false)
 	var extLength *uint8 = nil
-	if bool((lengthValueType) == (5)) {
+	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")
@@ -155,38 +177,67 @@ func BACnetTagParse(readBuffer utils.ReadBuffer) (*BACnetTag, error) {
 		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(uint32(utils.InlineIf(isPrimitiveAndNotBoolean, func() interface{} { return uint32(lengthValueType) }, func() interface{} { return uint32(uint32(0)) }).(uint32)))
+			}).(uint32)))
+		}).(uint32)))
+	}).(uint32)
+
 	// Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
 	var _parent *BACnetTag
 	var typeSwitchError error
 	switch {
-	case contextSpecificTag == 0 && typeOrTagNumber == 0x0: // BACnetTagApplicationNull
+	case tagClass == TagClass_APPLICATION_TAGS && tagNumber == 0x0: // BACnetTagApplicationNull
 		_parent, typeSwitchError = BACnetTagApplicationNullParse(readBuffer)
-	case contextSpecificTag == 0 && typeOrTagNumber == 0x1: // BACnetTagApplicationBoolean
+	case tagClass == TagClass_APPLICATION_TAGS && tagNumber == 0x1: // BACnetTagApplicationBoolean
 		_parent, typeSwitchError = BACnetTagApplicationBooleanParse(readBuffer)
-	case contextSpecificTag == 0 && typeOrTagNumber == 0x2: // BACnetTagApplicationUnsignedInteger
+	case tagClass == TagClass_APPLICATION_TAGS && tagNumber == 0x2: // BACnetTagApplicationUnsignedInteger
 		_parent, typeSwitchError = BACnetTagApplicationUnsignedIntegerParse(readBuffer, lengthValueType, *extLength)
-	case contextSpecificTag == 0 && typeOrTagNumber == 0x3: // BACnetTagApplicationSignedInteger
+	case tagClass == TagClass_APPLICATION_TAGS && tagNumber == 0x3: // BACnetTagApplicationSignedInteger
 		_parent, typeSwitchError = BACnetTagApplicationSignedIntegerParse(readBuffer, lengthValueType, *extLength)
-	case contextSpecificTag == 0 && typeOrTagNumber == 0x4: // BACnetTagApplicationReal
+	case tagClass == TagClass_APPLICATION_TAGS && tagNumber == 0x4: // BACnetTagApplicationReal
 		_parent, typeSwitchError = BACnetTagApplicationRealParse(readBuffer, lengthValueType, *extLength)
-	case contextSpecificTag == 0 && typeOrTagNumber == 0x5: // BACnetTagApplicationDouble
+	case tagClass == TagClass_APPLICATION_TAGS && tagNumber == 0x5: // BACnetTagApplicationDouble
 		_parent, typeSwitchError = BACnetTagApplicationDoubleParse(readBuffer, lengthValueType, *extLength)
-	case contextSpecificTag == 0 && typeOrTagNumber == 0x6: // BACnetTagApplicationOctetString
+	case tagClass == TagClass_APPLICATION_TAGS && tagNumber == 0x6: // BACnetTagApplicationOctetString
 		_parent, typeSwitchError = BACnetTagApplicationOctetStringParse(readBuffer)
-	case contextSpecificTag == 0 && typeOrTagNumber == 0x7: // BACnetTagApplicationCharacterString
+	case tagClass == TagClass_APPLICATION_TAGS && tagNumber == 0x7: // BACnetTagApplicationCharacterString
 		_parent, typeSwitchError = BACnetTagApplicationCharacterStringParse(readBuffer)
-	case contextSpecificTag == 0 && typeOrTagNumber == 0x8: // BACnetTagApplicationBitString
+	case tagClass == TagClass_APPLICATION_TAGS && tagNumber == 0x8: // BACnetTagApplicationBitString
 		_parent, typeSwitchError = BACnetTagApplicationBitStringParse(readBuffer, lengthValueType, *extLength)
-	case contextSpecificTag == 0 && typeOrTagNumber == 0x9: // BACnetTagApplicationEnumerated
+	case tagClass == TagClass_APPLICATION_TAGS && tagNumber == 0x9: // BACnetTagApplicationEnumerated
 		_parent, typeSwitchError = BACnetTagApplicationEnumeratedParse(readBuffer, lengthValueType, *extLength)
-	case contextSpecificTag == 0 && typeOrTagNumber == 0xA: // BACnetTagApplicationDate
+	case tagClass == TagClass_APPLICATION_TAGS && tagNumber == 0xA: // BACnetTagApplicationDate
 		_parent, typeSwitchError = BACnetTagApplicationDateParse(readBuffer)
-	case contextSpecificTag == 0 && typeOrTagNumber == 0xB: // BACnetTagApplicationTime
+	case tagClass == TagClass_APPLICATION_TAGS && tagNumber == 0xB: // BACnetTagApplicationTime
 		_parent, typeSwitchError = BACnetTagApplicationTimeParse(readBuffer)
-	case contextSpecificTag == 0 && typeOrTagNumber == 0xC: // BACnetTagApplicationObjectIdentifier
+	case tagClass == TagClass_APPLICATION_TAGS && tagNumber == 0xC: // BACnetTagApplicationObjectIdentifier
 		_parent, typeSwitchError = BACnetTagApplicationObjectIdentifierParse(readBuffer)
-	case contextSpecificTag == 1: // BACnetTagContext
-		_parent, typeSwitchError = BACnetTagContextParse(readBuffer, typeOrTagNumber, *extTagNumber, lengthValueType, *extLength)
+	case tagClass == TagClass_CONTEXT_SPECIFIC_TAGS: // BACnetTagContext
+		_parent, typeSwitchError = BACnetTagContextParse(readBuffer, tagNumber, *extTagNumber, lengthValueType, *extLength)
 	default:
 		// TODO: return actual type
 		typeSwitchError = errors.New("Unmapped type")
@@ -200,7 +251,7 @@ func BACnetTagParse(readBuffer utils.ReadBuffer) (*BACnetTag, error) {
 	}
 
 	// Finish initializing
-	_parent.Child.InitializeParent(_parent, typeOrTagNumber, lengthValueType, extTagNumber, extLength)
+	_parent.Child.InitializeParent(_parent, tagNumber, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength, isPrimitiveAndNotBoolean, actualLength)
 	return _parent, nil
 }
 
@@ -213,19 +264,19 @@ func (m *BACnetTag) SerializeParent(writeBuffer utils.WriteBuffer, child IBACnet
 		return pushErr
 	}
 
-	// Simple Field (typeOrTagNumber)
-	typeOrTagNumber := uint8(m.TypeOrTagNumber)
-	_typeOrTagNumberErr := writeBuffer.WriteUint8("typeOrTagNumber", 4, (typeOrTagNumber))
-	if _typeOrTagNumberErr != nil {
-		return errors.Wrap(_typeOrTagNumberErr, "Error serializing 'typeOrTagNumber' field")
+	// Simple Field (tagNumber)
+	tagNumber := uint8(m.TagNumber)
+	_tagNumberErr := writeBuffer.WriteUint8("tagNumber", 4, (tagNumber))
+	if _tagNumberErr != nil {
+		return errors.Wrap(_tagNumberErr, "Error serializing 'tagNumber' field")
 	}
 
-	// Discriminator Field (contextSpecificTag) (Used as input to a switch field)
-	contextSpecificTag := uint8(child.ContextSpecificTag())
-	_contextSpecificTagErr := writeBuffer.WriteUint8("contextSpecificTag", 1, (contextSpecificTag))
+	// Discriminator Field (tagClass) (Used as input to a switch field)
+	tagClass := TagClass(child.TagClass())
+	_tagClassErr := tagClass.Serialize(writeBuffer)
 
-	if _contextSpecificTagErr != nil {
-		return errors.Wrap(_contextSpecificTagErr, "Error serializing 'contextSpecificTag' field")
+	if _tagClassErr != nil {
+		return errors.Wrap(_tagClassErr, "Error serializing 'tagClass' field")
 	}
 
 	// Simple Field (lengthValueType)
@@ -255,6 +306,26 @@ func (m *BACnetTag) SerializeParent(writeBuffer utils.WriteBuffer, child IBACnet
 		}
 	}
 
+	// 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")
+		}
+	}
+
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
 	_typeSwitchErr := serializeChildFunction()
 	if _typeSwitchErr != nil {
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationBitString.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationBitString.go
index b03e664..6878d56 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationBitString.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationBitString.go
@@ -43,22 +43,24 @@ type IBACnetTagApplicationBitString interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
-func (m *BACnetTagApplicationBitString) ContextSpecificTag() uint8 {
-	return 0
+func (m *BACnetTagApplicationBitString) TagClass() TagClass {
+	return TagClass_APPLICATION_TAGS
 }
 
-func (m *BACnetTagApplicationBitString) InitializeParent(parent *BACnetTag, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) {
-	m.Parent.TypeOrTagNumber = typeOrTagNumber
+func (m *BACnetTagApplicationBitString) InitializeParent(parent *BACnetTag, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, isPrimitiveAndNotBoolean bool, actualLength uint32) {
+	m.Parent.TagNumber = tagNumber
 	m.Parent.LengthValueType = lengthValueType
 	m.Parent.ExtTagNumber = extTagNumber
 	m.Parent.ExtLength = extLength
+	m.Parent.ExtExtLength = extExtLength
+	m.Parent.ExtExtExtLength = extExtExtLength
 }
 
-func NewBACnetTagApplicationBitString(unusedBits uint8, data []int8, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) *BACnetTag {
+func NewBACnetTagApplicationBitString(unusedBits uint8, data []int8, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32) *BACnetTag {
 	child := &BACnetTagApplicationBitString{
 		UnusedBits: unusedBits,
 		Data:       data,
-		Parent:     NewBACnetTag(typeOrTagNumber, lengthValueType, extTagNumber, extLength),
+		Parent:     NewBACnetTag(tagNumber, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength),
 	}
 	child.Parent.Child = child
 	return child.Parent
@@ -126,7 +128,7 @@ func BACnetTagApplicationBitStringParse(readBuffer utils.ReadBuffer, lengthValue
 	}
 	// Length array
 	data := make([]int8, 0)
-	_dataLength := utils.InlineIf(bool(bool((lengthValueType) == (5))), func() uint16 { return uint16(uint16(uint16(extLength) - uint16(uint16(1)))) }, func() uint16 { return uint16(uint16(uint16(lengthValueType) - uint16(uint16(1)))) })
+	_dataLength := utils.InlineIf(bool(bool((lengthValueType) == (5))), func() interface{} { return uint16(uint16(uint16(extLength) - uint16(uint16(1)))) }, func() interface{} { return uint16(uint16(uint16(lengthValueType) - uint16(uint16(1)))) }).(uint16)
 	_dataEndPos := readBuffer.GetPos() + uint16(_dataLength)
 	for readBuffer.GetPos() < _dataEndPos {
 		_item, _err := readBuffer.ReadInt8("", 8)
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationBoolean.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationBoolean.go
index f99b845..c87c551 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationBoolean.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationBoolean.go
@@ -40,20 +40,22 @@ type IBACnetTagApplicationBoolean interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
-func (m *BACnetTagApplicationBoolean) ContextSpecificTag() uint8 {
-	return 0
+func (m *BACnetTagApplicationBoolean) TagClass() TagClass {
+	return TagClass_APPLICATION_TAGS
 }
 
-func (m *BACnetTagApplicationBoolean) InitializeParent(parent *BACnetTag, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) {
-	m.Parent.TypeOrTagNumber = typeOrTagNumber
+func (m *BACnetTagApplicationBoolean) InitializeParent(parent *BACnetTag, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, isPrimitiveAndNotBoolean bool, actualLength uint32) {
+	m.Parent.TagNumber = tagNumber
 	m.Parent.LengthValueType = lengthValueType
 	m.Parent.ExtTagNumber = extTagNumber
 	m.Parent.ExtLength = extLength
+	m.Parent.ExtExtLength = extExtLength
+	m.Parent.ExtExtExtLength = extExtExtLength
 }
 
-func NewBACnetTagApplicationBoolean(typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) *BACnetTag {
+func NewBACnetTagApplicationBoolean(tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32) *BACnetTag {
 	child := &BACnetTagApplicationBoolean{
-		Parent: NewBACnetTag(typeOrTagNumber, lengthValueType, extTagNumber, extLength),
+		Parent: NewBACnetTag(tagNumber, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength),
 	}
 	child.Parent.Child = child
 	return child.Parent
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationCharacterString.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationCharacterString.go
index 6e9d854..ac7c05c 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationCharacterString.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationCharacterString.go
@@ -40,20 +40,22 @@ type IBACnetTagApplicationCharacterString interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
-func (m *BACnetTagApplicationCharacterString) ContextSpecificTag() uint8 {
-	return 0
+func (m *BACnetTagApplicationCharacterString) TagClass() TagClass {
+	return TagClass_APPLICATION_TAGS
 }
 
-func (m *BACnetTagApplicationCharacterString) InitializeParent(parent *BACnetTag, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) {
-	m.Parent.TypeOrTagNumber = typeOrTagNumber
+func (m *BACnetTagApplicationCharacterString) InitializeParent(parent *BACnetTag, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, isPrimitiveAndNotBoolean bool, actualLength uint32) {
+	m.Parent.TagNumber = tagNumber
 	m.Parent.LengthValueType = lengthValueType
 	m.Parent.ExtTagNumber = extTagNumber
 	m.Parent.ExtLength = extLength
+	m.Parent.ExtExtLength = extExtLength
+	m.Parent.ExtExtExtLength = extExtExtLength
 }
 
-func NewBACnetTagApplicationCharacterString(typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) *BACnetTag {
+func NewBACnetTagApplicationCharacterString(tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32) *BACnetTag {
 	child := &BACnetTagApplicationCharacterString{
-		Parent: NewBACnetTag(typeOrTagNumber, lengthValueType, extTagNumber, extLength),
+		Parent: NewBACnetTag(tagNumber, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength),
 	}
 	child.Parent.Child = child
 	return child.Parent
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationDate.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationDate.go
index a348396..6fd8b3f 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationDate.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationDate.go
@@ -40,20 +40,22 @@ type IBACnetTagApplicationDate interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
-func (m *BACnetTagApplicationDate) ContextSpecificTag() uint8 {
-	return 0
+func (m *BACnetTagApplicationDate) TagClass() TagClass {
+	return TagClass_APPLICATION_TAGS
 }
 
-func (m *BACnetTagApplicationDate) InitializeParent(parent *BACnetTag, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) {
-	m.Parent.TypeOrTagNumber = typeOrTagNumber
+func (m *BACnetTagApplicationDate) InitializeParent(parent *BACnetTag, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, isPrimitiveAndNotBoolean bool, actualLength uint32) {
+	m.Parent.TagNumber = tagNumber
 	m.Parent.LengthValueType = lengthValueType
 	m.Parent.ExtTagNumber = extTagNumber
 	m.Parent.ExtLength = extLength
+	m.Parent.ExtExtLength = extExtLength
+	m.Parent.ExtExtExtLength = extExtExtLength
 }
 
-func NewBACnetTagApplicationDate(typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) *BACnetTag {
+func NewBACnetTagApplicationDate(tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32) *BACnetTag {
 	child := &BACnetTagApplicationDate{
-		Parent: NewBACnetTag(typeOrTagNumber, lengthValueType, extTagNumber, extLength),
+		Parent: NewBACnetTag(tagNumber, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength),
 	}
 	child.Parent.Child = child
 	return child.Parent
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationDouble.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationDouble.go
index 654db92..282de13 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationDouble.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationDouble.go
@@ -42,21 +42,23 @@ type IBACnetTagApplicationDouble interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
-func (m *BACnetTagApplicationDouble) ContextSpecificTag() uint8 {
-	return 0
+func (m *BACnetTagApplicationDouble) TagClass() TagClass {
+	return TagClass_APPLICATION_TAGS
 }
 
-func (m *BACnetTagApplicationDouble) InitializeParent(parent *BACnetTag, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) {
-	m.Parent.TypeOrTagNumber = typeOrTagNumber
+func (m *BACnetTagApplicationDouble) InitializeParent(parent *BACnetTag, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, isPrimitiveAndNotBoolean bool, actualLength uint32) {
+	m.Parent.TagNumber = tagNumber
 	m.Parent.LengthValueType = lengthValueType
 	m.Parent.ExtTagNumber = extTagNumber
 	m.Parent.ExtLength = extLength
+	m.Parent.ExtExtLength = extExtLength
+	m.Parent.ExtExtExtLength = extExtExtLength
 }
 
-func NewBACnetTagApplicationDouble(value float64, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) *BACnetTag {
+func NewBACnetTagApplicationDouble(value float64, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32) *BACnetTag {
 	child := &BACnetTagApplicationDouble{
 		Value:  value,
-		Parent: NewBACnetTag(typeOrTagNumber, lengthValueType, extTagNumber, extLength),
+		Parent: NewBACnetTag(tagNumber, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength),
 	}
 	child.Parent.Child = child
 	return child.Parent
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationEnumerated.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationEnumerated.go
index 6e90eb6..24b3589 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationEnumerated.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationEnumerated.go
@@ -42,21 +42,23 @@ type IBACnetTagApplicationEnumerated interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
-func (m *BACnetTagApplicationEnumerated) ContextSpecificTag() uint8 {
-	return 0
+func (m *BACnetTagApplicationEnumerated) TagClass() TagClass {
+	return TagClass_APPLICATION_TAGS
 }
 
-func (m *BACnetTagApplicationEnumerated) InitializeParent(parent *BACnetTag, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) {
-	m.Parent.TypeOrTagNumber = typeOrTagNumber
+func (m *BACnetTagApplicationEnumerated) InitializeParent(parent *BACnetTag, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, isPrimitiveAndNotBoolean bool, actualLength uint32) {
+	m.Parent.TagNumber = tagNumber
 	m.Parent.LengthValueType = lengthValueType
 	m.Parent.ExtTagNumber = extTagNumber
 	m.Parent.ExtLength = extLength
+	m.Parent.ExtExtLength = extExtLength
+	m.Parent.ExtExtExtLength = extExtExtLength
 }
 
-func NewBACnetTagApplicationEnumerated(data []int8, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) *BACnetTag {
+func NewBACnetTagApplicationEnumerated(data []int8, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32) *BACnetTag {
 	child := &BACnetTagApplicationEnumerated{
 		Data:   data,
-		Parent: NewBACnetTag(typeOrTagNumber, lengthValueType, extTagNumber, extLength),
+		Parent: NewBACnetTag(tagNumber, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength),
 	}
 	child.Parent.Child = child
 	return child.Parent
@@ -115,7 +117,7 @@ func BACnetTagApplicationEnumeratedParse(readBuffer utils.ReadBuffer, lengthValu
 	}
 	// Length array
 	data := make([]int8, 0)
-	_dataLength := utils.InlineIf(bool(bool((lengthValueType) == (5))), func() uint16 { return uint16(extLength) }, func() uint16 { return uint16(lengthValueType) })
+	_dataLength := utils.InlineIf(bool(bool((lengthValueType) == (5))), func() interface{} { return uint16(extLength) }, func() interface{} { return uint16(lengthValueType) }).(uint16)
 	_dataEndPos := readBuffer.GetPos() + uint16(_dataLength)
 	for readBuffer.GetPos() < _dataEndPos {
 		_item, _err := readBuffer.ReadInt8("", 8)
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationNull.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationNull.go
index ece8d50..44bf4ec 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationNull.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationNull.go
@@ -40,20 +40,22 @@ type IBACnetTagApplicationNull interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
-func (m *BACnetTagApplicationNull) ContextSpecificTag() uint8 {
-	return 0
+func (m *BACnetTagApplicationNull) TagClass() TagClass {
+	return TagClass_APPLICATION_TAGS
 }
 
-func (m *BACnetTagApplicationNull) InitializeParent(parent *BACnetTag, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) {
-	m.Parent.TypeOrTagNumber = typeOrTagNumber
+func (m *BACnetTagApplicationNull) InitializeParent(parent *BACnetTag, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, isPrimitiveAndNotBoolean bool, actualLength uint32) {
+	m.Parent.TagNumber = tagNumber
 	m.Parent.LengthValueType = lengthValueType
 	m.Parent.ExtTagNumber = extTagNumber
 	m.Parent.ExtLength = extLength
+	m.Parent.ExtExtLength = extExtLength
+	m.Parent.ExtExtExtLength = extExtExtLength
 }
 
-func NewBACnetTagApplicationNull(typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) *BACnetTag {
+func NewBACnetTagApplicationNull(tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32) *BACnetTag {
 	child := &BACnetTagApplicationNull{
-		Parent: NewBACnetTag(typeOrTagNumber, lengthValueType, extTagNumber, extLength),
+		Parent: NewBACnetTag(tagNumber, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength),
 	}
 	child.Parent.Child = child
 	return child.Parent
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationObjectIdentifier.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationObjectIdentifier.go
index abc5569..b593fd1 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationObjectIdentifier.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationObjectIdentifier.go
@@ -40,20 +40,22 @@ type IBACnetTagApplicationObjectIdentifier interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
-func (m *BACnetTagApplicationObjectIdentifier) ContextSpecificTag() uint8 {
-	return 0
+func (m *BACnetTagApplicationObjectIdentifier) TagClass() TagClass {
+	return TagClass_APPLICATION_TAGS
 }
 
-func (m *BACnetTagApplicationObjectIdentifier) InitializeParent(parent *BACnetTag, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) {
-	m.Parent.TypeOrTagNumber = typeOrTagNumber
+func (m *BACnetTagApplicationObjectIdentifier) InitializeParent(parent *BACnetTag, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, isPrimitiveAndNotBoolean bool, actualLength uint32) {
+	m.Parent.TagNumber = tagNumber
 	m.Parent.LengthValueType = lengthValueType
 	m.Parent.ExtTagNumber = extTagNumber
 	m.Parent.ExtLength = extLength
+	m.Parent.ExtExtLength = extExtLength
+	m.Parent.ExtExtExtLength = extExtExtLength
 }
 
-func NewBACnetTagApplicationObjectIdentifier(typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) *BACnetTag {
+func NewBACnetTagApplicationObjectIdentifier(tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32) *BACnetTag {
 	child := &BACnetTagApplicationObjectIdentifier{
-		Parent: NewBACnetTag(typeOrTagNumber, lengthValueType, extTagNumber, extLength),
+		Parent: NewBACnetTag(tagNumber, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength),
 	}
 	child.Parent.Child = child
 	return child.Parent
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationOctetString.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationOctetString.go
index 8e6c4f4..dd33c8b 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationOctetString.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationOctetString.go
@@ -40,20 +40,22 @@ type IBACnetTagApplicationOctetString interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
-func (m *BACnetTagApplicationOctetString) ContextSpecificTag() uint8 {
-	return 0
+func (m *BACnetTagApplicationOctetString) TagClass() TagClass {
+	return TagClass_APPLICATION_TAGS
 }
 
-func (m *BACnetTagApplicationOctetString) InitializeParent(parent *BACnetTag, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) {
-	m.Parent.TypeOrTagNumber = typeOrTagNumber
+func (m *BACnetTagApplicationOctetString) InitializeParent(parent *BACnetTag, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, isPrimitiveAndNotBoolean bool, actualLength uint32) {
+	m.Parent.TagNumber = tagNumber
 	m.Parent.LengthValueType = lengthValueType
 	m.Parent.ExtTagNumber = extTagNumber
 	m.Parent.ExtLength = extLength
+	m.Parent.ExtExtLength = extExtLength
+	m.Parent.ExtExtExtLength = extExtExtLength
 }
 
-func NewBACnetTagApplicationOctetString(typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) *BACnetTag {
+func NewBACnetTagApplicationOctetString(tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32) *BACnetTag {
 	child := &BACnetTagApplicationOctetString{
-		Parent: NewBACnetTag(typeOrTagNumber, lengthValueType, extTagNumber, extLength),
+		Parent: NewBACnetTag(tagNumber, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength),
 	}
 	child.Parent.Child = child
 	return child.Parent
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationReal.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationReal.go
index 98036f5..d616879 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationReal.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationReal.go
@@ -42,21 +42,23 @@ type IBACnetTagApplicationReal interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
-func (m *BACnetTagApplicationReal) ContextSpecificTag() uint8 {
-	return 0
+func (m *BACnetTagApplicationReal) TagClass() TagClass {
+	return TagClass_APPLICATION_TAGS
 }
 
-func (m *BACnetTagApplicationReal) InitializeParent(parent *BACnetTag, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) {
-	m.Parent.TypeOrTagNumber = typeOrTagNumber
+func (m *BACnetTagApplicationReal) InitializeParent(parent *BACnetTag, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, isPrimitiveAndNotBoolean bool, actualLength uint32) {
+	m.Parent.TagNumber = tagNumber
 	m.Parent.LengthValueType = lengthValueType
 	m.Parent.ExtTagNumber = extTagNumber
 	m.Parent.ExtLength = extLength
+	m.Parent.ExtExtLength = extExtLength
+	m.Parent.ExtExtExtLength = extExtExtLength
 }
 
-func NewBACnetTagApplicationReal(value float32, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) *BACnetTag {
+func NewBACnetTagApplicationReal(value float32, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32) *BACnetTag {
 	child := &BACnetTagApplicationReal{
 		Value:  value,
-		Parent: NewBACnetTag(typeOrTagNumber, lengthValueType, extTagNumber, extLength),
+		Parent: NewBACnetTag(tagNumber, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength),
 	}
 	child.Parent.Child = child
 	return child.Parent
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationSignedInteger.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationSignedInteger.go
index eb91000..534d40a 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationSignedInteger.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationSignedInteger.go
@@ -42,21 +42,23 @@ type IBACnetTagApplicationSignedInteger interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
-func (m *BACnetTagApplicationSignedInteger) ContextSpecificTag() uint8 {
-	return 0
+func (m *BACnetTagApplicationSignedInteger) TagClass() TagClass {
+	return TagClass_APPLICATION_TAGS
 }
 
-func (m *BACnetTagApplicationSignedInteger) InitializeParent(parent *BACnetTag, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) {
-	m.Parent.TypeOrTagNumber = typeOrTagNumber
+func (m *BACnetTagApplicationSignedInteger) InitializeParent(parent *BACnetTag, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, isPrimitiveAndNotBoolean bool, actualLength uint32) {
+	m.Parent.TagNumber = tagNumber
 	m.Parent.LengthValueType = lengthValueType
 	m.Parent.ExtTagNumber = extTagNumber
 	m.Parent.ExtLength = extLength
+	m.Parent.ExtExtLength = extExtLength
+	m.Parent.ExtExtExtLength = extExtExtLength
 }
 
-func NewBACnetTagApplicationSignedInteger(data []int8, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) *BACnetTag {
+func NewBACnetTagApplicationSignedInteger(data []int8, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32) *BACnetTag {
 	child := &BACnetTagApplicationSignedInteger{
 		Data:   data,
-		Parent: NewBACnetTag(typeOrTagNumber, lengthValueType, extTagNumber, extLength),
+		Parent: NewBACnetTag(tagNumber, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength),
 	}
 	child.Parent.Child = child
 	return child.Parent
@@ -115,7 +117,7 @@ func BACnetTagApplicationSignedIntegerParse(readBuffer utils.ReadBuffer, lengthV
 	}
 	// Length array
 	data := make([]int8, 0)
-	_dataLength := utils.InlineIf(bool(bool((lengthValueType) == (5))), func() uint16 { return uint16(extLength) }, func() uint16 { return uint16(lengthValueType) })
+	_dataLength := utils.InlineIf(bool(bool((lengthValueType) == (5))), func() interface{} { return uint16(extLength) }, func() interface{} { return uint16(lengthValueType) }).(uint16)
 	_dataEndPos := readBuffer.GetPos() + uint16(_dataLength)
 	for readBuffer.GetPos() < _dataEndPos {
 		_item, _err := readBuffer.ReadInt8("", 8)
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationTime.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationTime.go
index cf34725..ad79fb5 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationTime.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationTime.go
@@ -40,20 +40,22 @@ type IBACnetTagApplicationTime interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
-func (m *BACnetTagApplicationTime) ContextSpecificTag() uint8 {
-	return 0
+func (m *BACnetTagApplicationTime) TagClass() TagClass {
+	return TagClass_APPLICATION_TAGS
 }
 
-func (m *BACnetTagApplicationTime) InitializeParent(parent *BACnetTag, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) {
-	m.Parent.TypeOrTagNumber = typeOrTagNumber
+func (m *BACnetTagApplicationTime) InitializeParent(parent *BACnetTag, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, isPrimitiveAndNotBoolean bool, actualLength uint32) {
+	m.Parent.TagNumber = tagNumber
 	m.Parent.LengthValueType = lengthValueType
 	m.Parent.ExtTagNumber = extTagNumber
 	m.Parent.ExtLength = extLength
+	m.Parent.ExtExtLength = extExtLength
+	m.Parent.ExtExtExtLength = extExtExtLength
 }
 
-func NewBACnetTagApplicationTime(typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) *BACnetTag {
+func NewBACnetTagApplicationTime(tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32) *BACnetTag {
 	child := &BACnetTagApplicationTime{
-		Parent: NewBACnetTag(typeOrTagNumber, lengthValueType, extTagNumber, extLength),
+		Parent: NewBACnetTag(tagNumber, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength),
 	}
 	child.Parent.Child = child
 	return child.Parent
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationUnsignedInteger.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationUnsignedInteger.go
index 4e17782..1453508 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationUnsignedInteger.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationUnsignedInteger.go
@@ -42,21 +42,23 @@ type IBACnetTagApplicationUnsignedInteger interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
-func (m *BACnetTagApplicationUnsignedInteger) ContextSpecificTag() uint8 {
-	return 0
+func (m *BACnetTagApplicationUnsignedInteger) TagClass() TagClass {
+	return TagClass_APPLICATION_TAGS
 }
 
-func (m *BACnetTagApplicationUnsignedInteger) InitializeParent(parent *BACnetTag, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) {
-	m.Parent.TypeOrTagNumber = typeOrTagNumber
+func (m *BACnetTagApplicationUnsignedInteger) InitializeParent(parent *BACnetTag, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, isPrimitiveAndNotBoolean bool, actualLength uint32) {
+	m.Parent.TagNumber = tagNumber
 	m.Parent.LengthValueType = lengthValueType
 	m.Parent.ExtTagNumber = extTagNumber
 	m.Parent.ExtLength = extLength
+	m.Parent.ExtExtLength = extExtLength
+	m.Parent.ExtExtExtLength = extExtExtLength
 }
 
-func NewBACnetTagApplicationUnsignedInteger(data []int8, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) *BACnetTag {
+func NewBACnetTagApplicationUnsignedInteger(data []int8, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32) *BACnetTag {
 	child := &BACnetTagApplicationUnsignedInteger{
 		Data:   data,
-		Parent: NewBACnetTag(typeOrTagNumber, lengthValueType, extTagNumber, extLength),
+		Parent: NewBACnetTag(tagNumber, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength),
 	}
 	child.Parent.Child = child
 	return child.Parent
@@ -115,7 +117,7 @@ func BACnetTagApplicationUnsignedIntegerParse(readBuffer utils.ReadBuffer, lengt
 	}
 	// Length array
 	data := make([]int8, 0)
-	_dataLength := utils.InlineIf(bool(bool((lengthValueType) == (5))), func() uint16 { return uint16(extLength) }, func() uint16 { return uint16(lengthValueType) })
+	_dataLength := utils.InlineIf(bool(bool((lengthValueType) == (5))), func() interface{} { return uint16(extLength) }, func() interface{} { return uint16(lengthValueType) }).(uint16)
 	_dataEndPos := readBuffer.GetPos() + uint16(_dataLength)
 	for readBuffer.GetPos() < _dataEndPos {
 		_item, _err := readBuffer.ReadInt8("", 8)
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagContext.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagContext.go
index 41c0d22..2cfff48 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagContext.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagContext.go
@@ -42,21 +42,23 @@ type IBACnetTagContext interface {
 ///////////////////////////////////////////////////////////
 // Accessors for discriminator values.
 ///////////////////////////////////////////////////////////
-func (m *BACnetTagContext) ContextSpecificTag() uint8 {
-	return 1
+func (m *BACnetTagContext) TagClass() TagClass {
+	return TagClass_CONTEXT_SPECIFIC_TAGS
 }
 
-func (m *BACnetTagContext) InitializeParent(parent *BACnetTag, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) {
-	m.Parent.TypeOrTagNumber = typeOrTagNumber
+func (m *BACnetTagContext) InitializeParent(parent *BACnetTag, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32, isPrimitiveAndNotBoolean bool, actualLength uint32) {
+	m.Parent.TagNumber = tagNumber
 	m.Parent.LengthValueType = lengthValueType
 	m.Parent.ExtTagNumber = extTagNumber
 	m.Parent.ExtLength = extLength
+	m.Parent.ExtExtLength = extExtLength
+	m.Parent.ExtExtExtLength = extExtExtLength
 }
 
-func NewBACnetTagContext(data []int8, typeOrTagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8) *BACnetTag {
+func NewBACnetTagContext(data []int8, tagNumber uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, extExtLength *uint16, extExtExtLength *uint32) *BACnetTag {
 	child := &BACnetTagContext{
 		Data:   data,
-		Parent: NewBACnetTag(typeOrTagNumber, lengthValueType, extTagNumber, extLength),
+		Parent: NewBACnetTag(tagNumber, lengthValueType, extTagNumber, extLength, extExtLength, extExtExtLength),
 	}
 	child.Parent.Child = child
 	return child.Parent
@@ -104,7 +106,7 @@ func (m *BACnetTagContext) LengthInBytes() uint16 {
 	return m.LengthInBits() / 8
 }
 
-func BACnetTagContextParse(readBuffer utils.ReadBuffer, typeOrTagNumber uint8, extTagNumber uint8, lengthValueType uint8, extLength uint8) (*BACnetTag, error) {
+func BACnetTagContextParse(readBuffer utils.ReadBuffer, tagNumber uint8, extTagNumber uint8, lengthValueType uint8, extLength uint8) (*BACnetTag, error) {
 	if pullErr := readBuffer.PullContext("BACnetTagContext"); pullErr != nil {
 		return nil, pullErr
 	}
@@ -115,7 +117,7 @@ func BACnetTagContextParse(readBuffer utils.ReadBuffer, typeOrTagNumber uint8, e
 	}
 	// Length array
 	data := make([]int8, 0)
-	_dataLength := utils.InlineIf(bool(bool((lengthValueType) == (5))), func() uint16 { return uint16(extLength) }, func() uint16 { return uint16(lengthValueType) })
+	_dataLength := utils.InlineIf(bool(bool((lengthValueType) == (5))), func() interface{} { return uint16(extLength) }, func() interface{} { return uint16(lengthValueType) }).(uint16)
 	_dataEndPos := readBuffer.GetPos() + uint16(_dataLength)
 	for readBuffer.GetPos() < _dataEndPos {
 		_item, _err := readBuffer.ReadInt8("", 8)
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagWithContent.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagWithContent.go
index 6e8b788..38de111 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagWithContent.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagWithContent.go
@@ -33,8 +33,8 @@ const BACnetTagWithContent_CLOSINGTAG uint8 = 0x2f
 
 // The data-structure of this message
 type BACnetTagWithContent struct {
-	TypeOrTagNumber    uint8
-	ContextSpecificTag uint8
+	TagNumber          uint8
+	TagClass           TagClass
 	LengthValueType    uint8
 	ExtTagNumber       *uint8
 	ExtLength          *uint8
@@ -49,8 +49,8 @@ type IBACnetTagWithContent interface {
 	Serialize(writeBuffer utils.WriteBuffer) error
 }
 
-func NewBACnetTagWithContent(typeOrTagNumber uint8, contextSpecificTag uint8, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, propertyIdentifier []uint8, value *BACnetTag) *BACnetTagWithContent {
-	return &BACnetTagWithContent{TypeOrTagNumber: typeOrTagNumber, ContextSpecificTag: contextSpecificTag, LengthValueType: lengthValueType, ExtTagNumber: extTagNumber, ExtLength: extLength, PropertyIdentifier: propertyIdentifier, Value: value}
+func NewBACnetTagWithContent(tagNumber uint8, tagClass TagClass, lengthValueType uint8, extTagNumber *uint8, extLength *uint8, propertyIdentifier []uint8, value *BACnetTag) *BACnetTagWithContent {
+	return &BACnetTagWithContent{TagNumber: tagNumber, TagClass: tagClass, LengthValueType: lengthValueType, ExtTagNumber: extTagNumber, ExtLength: extLength, PropertyIdentifier: propertyIdentifier, Value: value}
 }
 
 func CastBACnetTagWithContent(structType interface{}) *BACnetTagWithContent {
@@ -77,10 +77,10 @@ func (m *BACnetTagWithContent) LengthInBits() uint16 {
 func (m *BACnetTagWithContent) LengthInBitsConditional(lastItem bool) uint16 {
 	lengthInBits := uint16(0)
 
-	// Simple field (typeOrTagNumber)
+	// Simple field (tagNumber)
 	lengthInBits += 4
 
-	// Simple field (contextSpecificTag)
+	// Simple field (tagClass)
 	lengthInBits += 1
 
 	// Simple field (lengthValueType)
@@ -122,16 +122,22 @@ func BACnetTagWithContentParse(readBuffer utils.ReadBuffer) (*BACnetTagWithConte
 		return nil, pullErr
 	}
 
-	// Simple Field (typeOrTagNumber)
-	typeOrTagNumber, _typeOrTagNumberErr := readBuffer.ReadUint8("typeOrTagNumber", 4)
-	if _typeOrTagNumberErr != nil {
-		return nil, errors.Wrap(_typeOrTagNumberErr, "Error parsing 'typeOrTagNumber' field")
+	// Simple Field (tagNumber)
+	tagNumber, _tagNumberErr := readBuffer.ReadUint8("tagNumber", 4)
+	if _tagNumberErr != nil {
+		return nil, errors.Wrap(_tagNumberErr, "Error parsing 'tagNumber' field")
 	}
 
-	// Simple Field (contextSpecificTag)
-	contextSpecificTag, _contextSpecificTagErr := readBuffer.ReadUint8("contextSpecificTag", 1)
-	if _contextSpecificTagErr != nil {
-		return nil, errors.Wrap(_contextSpecificTagErr, "Error parsing 'contextSpecificTag' field")
+	// 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")
+	}
+	if closeErr := readBuffer.CloseContext("tagClass"); closeErr != nil {
+		return nil, closeErr
 	}
 
 	// Simple Field (lengthValueType)
@@ -142,7 +148,7 @@ func BACnetTagWithContentParse(readBuffer utils.ReadBuffer) (*BACnetTagWithConte
 
 	// Optional Field (extTagNumber) (Can be skipped, if a given expression evaluates to false)
 	var extTagNumber *uint8 = nil
-	if bool((typeOrTagNumber) == (15)) {
+	if bool((tagNumber) == (15)) {
 		_val, _err := readBuffer.ReadUint8("extTagNumber", 8)
 		if _err != nil {
 			return nil, errors.Wrap(_err, "Error parsing 'extTagNumber' field")
@@ -166,7 +172,7 @@ func BACnetTagWithContentParse(readBuffer utils.ReadBuffer) (*BACnetTagWithConte
 	}
 	// Length array
 	propertyIdentifier := make([]uint8, 0)
-	_propertyIdentifierLength := utils.InlineIf(bool(bool((lengthValueType) == (5))), func() uint16 { return uint16((*extLength)) }, func() uint16 { return uint16(lengthValueType) })
+	_propertyIdentifierLength := utils.InlineIf(bool(bool((lengthValueType) == (5))), func() interface{} { return uint16((*extLength)) }, func() interface{} { return uint16(lengthValueType) }).(uint16)
 	_propertyIdentifierEndPos := readBuffer.GetPos() + uint16(_propertyIdentifierLength)
 	for readBuffer.GetPos() < _propertyIdentifierEndPos {
 		_item, _err := readBuffer.ReadUint8("", 8)
@@ -214,7 +220,7 @@ func BACnetTagWithContentParse(readBuffer utils.ReadBuffer) (*BACnetTagWithConte
 	}
 
 	// Create the instance
-	return NewBACnetTagWithContent(typeOrTagNumber, contextSpecificTag, lengthValueType, extTagNumber, extLength, propertyIdentifier, value), nil
+	return NewBACnetTagWithContent(tagNumber, tagClass, lengthValueType, extTagNumber, extLength, propertyIdentifier, value), nil
 }
 
 func (m *BACnetTagWithContent) Serialize(writeBuffer utils.WriteBuffer) error {
@@ -222,18 +228,23 @@ func (m *BACnetTagWithContent) Serialize(writeBuffer utils.WriteBuffer) error {
 		return pushErr
 	}
 
-	// Simple Field (typeOrTagNumber)
-	typeOrTagNumber := uint8(m.TypeOrTagNumber)
-	_typeOrTagNumberErr := writeBuffer.WriteUint8("typeOrTagNumber", 4, (typeOrTagNumber))
-	if _typeOrTagNumberErr != nil {
-		return errors.Wrap(_typeOrTagNumberErr, "Error serializing 'typeOrTagNumber' field")
+	// 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 (contextSpecificTag)
-	contextSpecificTag := uint8(m.ContextSpecificTag)
-	_contextSpecificTagErr := writeBuffer.WriteUint8("contextSpecificTag", 1, (contextSpecificTag))
-	if _contextSpecificTagErr != nil {
-		return errors.Wrap(_contextSpecificTagErr, "Error serializing 'contextSpecificTag' 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)
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/NLMIAmRouterToNetwork.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/NLMIAmRouterToNetwork.go
index b825317..60ea771 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/NLMIAmRouterToNetwork.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/NLMIAmRouterToNetwork.go
@@ -112,7 +112,7 @@ func NLMIAmRouterToNetworkParse(readBuffer utils.ReadBuffer, apduLength uint16,
 	}
 	// Length array
 	destinationNetworkAddress := make([]uint16, 0)
-	_destinationNetworkAddressLength := uint16(apduLength) - uint16(uint16(utils.InlineIf(bool(bool(bool(bool((messageType) >= (128)))) && bool(bool(bool((messageType) <= (255))))), func() uint16 { return uint16(uint16(3)) }, func() uint16 { return uint16(uint16(1)) })))
+	_destinationNetworkAddressLength := uint16(apduLength) - uint16(uint16(utils.InlineIf(bool(bool(bool(bool((messageType) >= (128)))) && bool(bool(bool((messageType) <= (255))))), func() interface{} { return uint16(uint16(3)) }, func() interface{} { return uint16(uint16(1)) }).(uint16)))
 	_destinationNetworkAddressEndPos := readBuffer.GetPos() + uint16(_destinationNetworkAddressLength)
 	for readBuffer.GetPos() < _destinationNetworkAddressEndPos {
 		_item, _err := readBuffer.ReadUint16("", 16)
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/NLMWhoIsRouterToNetwork.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/NLMWhoIsRouterToNetwork.go
index c0d1cf0..b56129b 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/NLMWhoIsRouterToNetwork.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/NLMWhoIsRouterToNetwork.go
@@ -112,7 +112,7 @@ func NLMWhoIsRouterToNetworkParse(readBuffer utils.ReadBuffer, apduLength uint16
 	}
 	// Length array
 	destinationNetworkAddress := make([]uint16, 0)
-	_destinationNetworkAddressLength := uint16(apduLength) - uint16(uint16(utils.InlineIf(bool(bool(bool(bool((messageType) >= (128)))) && bool(bool(bool((messageType) <= (255))))), func() uint16 { return uint16(uint16(3)) }, func() uint16 { return uint16(uint16(1)) })))
+	_destinationNetworkAddressLength := uint16(apduLength) - uint16(uint16(utils.InlineIf(bool(bool(bool(bool((messageType) >= (128)))) && bool(bool(bool((messageType) <= (255))))), func() interface{} { return uint16(uint16(3)) }, func() interface{} { return uint16(uint16(1)) }).(uint16)))
 	_destinationNetworkAddressEndPos := readBuffer.GetPos() + uint16(_destinationNetworkAddressLength)
 	for readBuffer.GetPos() < _destinationNetworkAddressEndPos {
 		_item, _err := readBuffer.ReadUint16("", 16)
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/NPDU.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/NPDU.go
index 4b3e6fb..6506ea6 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/NPDU.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/NPDU.go
@@ -251,8 +251,8 @@ func NPDUParse(readBuffer utils.ReadBuffer, npduLength uint16) (*NPDU, error) {
 		return nil, pullErr
 	}
 	// Count array
-	destinationAddress := make([]uint8, utils.InlineIf(destinationSpecified, func() uint16 { return uint16((*destinationLength)) }, func() uint16 { return uint16(uint16(0)) }))
-	for curItem := uint16(0); curItem < uint16(utils.InlineIf(destinationSpecified, func() uint16 { return uint16((*destinationLength)) }, func() uint16 { return uint16(uint16(0)) })); curItem++ {
+	destinationAddress := make([]uint8, utils.InlineIf(destinationSpecified, func() interface{} { return uint16((*destinationLength)) }, func() interface{} { return uint16(uint16(0)) }).(uint16))
+	for curItem := uint16(0); curItem < uint16(utils.InlineIf(destinationSpecified, func() interface{} { return uint16((*destinationLength)) }, func() interface{} { return uint16(uint16(0)) }).(uint16)); curItem++ {
 		_item, _err := readBuffer.ReadUint8("", 8)
 		if _err != nil {
 			return nil, errors.Wrap(_err, "Error parsing 'destinationAddress' field")
@@ -288,8 +288,8 @@ func NPDUParse(readBuffer utils.ReadBuffer, npduLength uint16) (*NPDU, error) {
 		return nil, pullErr
 	}
 	// Count array
-	sourceAddress := make([]uint8, utils.InlineIf(sourceSpecified, func() uint16 { return uint16((*sourceLength)) }, func() uint16 { return uint16(uint16(0)) }))
-	for curItem := uint16(0); curItem < uint16(utils.InlineIf(sourceSpecified, func() uint16 { return uint16((*sourceLength)) }, func() uint16 { return uint16(uint16(0)) })); curItem++ {
+	sourceAddress := make([]uint8, utils.InlineIf(sourceSpecified, func() interface{} { return uint16((*sourceLength)) }, func() interface{} { return uint16(uint16(0)) }).(uint16))
+	for curItem := uint16(0); curItem < uint16(utils.InlineIf(sourceSpecified, func() interface{} { return uint16((*sourceLength)) }, func() interface{} { return uint16(uint16(0)) }).(uint16)); curItem++ {
 		_item, _err := readBuffer.ReadUint8("", 8)
 		if _err != nil {
 			return nil, errors.Wrap(_err, "Error parsing 'sourceAddress' field")
@@ -313,7 +313,7 @@ func NPDUParse(readBuffer utils.ReadBuffer, npduLength uint16) (*NPDU, error) {
 	// Optional Field (nlm) (Can be skipped, if a given expression evaluates to false)
 	var nlm *NLM = nil
 	if messageTypeFieldPresent {
-		_val, _err := NLMParse(readBuffer, uint16(npduLength)-uint16(uint16(uint16(uint16(uint16(uint16(2))+uint16(uint16(utils.InlineIf(sourceSpecified, func() uint16 { return uint16(uint16(uint16(3)) + uint16((*sourceLength))) }, func() uint16 { return uint16(uint16(0)) }))))+uint16(uint16(utils.InlineIf(destinationSpecified, func() uint16 { return uint16(uint16(uint16(3)) + uint16((*destinationLength))) }, func() uint16 { return uint16(uint16(0)) }))))+uint16(uint16(utils.InlineIf(bool(bool [...]
+		_val, _err := NLMParse(readBuffer, uint16(npduLength)-uint16(uint16(uint16(uint16(uint16(uint16(2))+uint16(uint16(utils.InlineIf(sourceSpecified, func() interface{} { return uint16(uint16(uint16(3)) + uint16((*sourceLength))) }, func() interface{} { return uint16(uint16(0)) }).(uint16))))+uint16(uint16(utils.InlineIf(destinationSpecified, func() interface{} { return uint16(uint16(uint16(3)) + uint16((*destinationLength))) }, func() interface{} { return uint16(uint16(0)) }).(uint16))))+ [...]
 		if _err != nil {
 			return nil, errors.Wrap(_err, "Error parsing 'nlm' field")
 		}
@@ -323,7 +323,7 @@ func NPDUParse(readBuffer utils.ReadBuffer, npduLength uint16) (*NPDU, error) {
 	// Optional Field (apdu) (Can be skipped, if a given expression evaluates to false)
 	var apdu *APDU = nil
 	if !(messageTypeFieldPresent) {
-		_val, _err := APDUParse(readBuffer, uint16(npduLength)-uint16(uint16(uint16(uint16(uint16(uint16(2))+uint16(uint16(utils.InlineIf(sourceSpecified, func() uint16 { return uint16(uint16(uint16(3)) + uint16((*sourceLength))) }, func() uint16 { return uint16(uint16(0)) }))))+uint16(uint16(utils.InlineIf(destinationSpecified, func() uint16 { return uint16(uint16(uint16(3)) + uint16((*destinationLength))) }, func() uint16 { return uint16(uint16(0)) }))))+uint16(uint16(utils.InlineIf(bool(boo [...]
+		_val, _err := APDUParse(readBuffer, uint16(npduLength)-uint16(uint16(uint16(uint16(uint16(uint16(2))+uint16(uint16(utils.InlineIf(sourceSpecified, func() interface{} { return uint16(uint16(uint16(3)) + uint16((*sourceLength))) }, func() interface{} { return uint16(uint16(0)) }).(uint16))))+uint16(uint16(utils.InlineIf(destinationSpecified, func() interface{} { return uint16(uint16(uint16(3)) + uint16((*destinationLength))) }, func() interface{} { return uint16(uint16(0)) }).(uint16)))) [...]
 		if _err != nil {
 			return nil, errors.Wrap(_err, "Error parsing 'apdu' field")
 		}
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/TagClass.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/TagClass.go
new file mode 100644
index 0000000..f3b5308
--- /dev/null
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/TagClass.go
@@ -0,0 +1,112 @@
+/*
+ * 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.
+
+type TagClass uint8
+
+type ITagClass interface {
+	Serialize(writeBuffer utils.WriteBuffer) error
+}
+
+const (
+	TagClass_APPLICATION_TAGS      TagClass = 0x0
+	TagClass_CONTEXT_SPECIFIC_TAGS TagClass = 0x1
+)
+
+var TagClassValues []TagClass
+
+func init() {
+	_ = errors.New
+	TagClassValues = []TagClass{
+		TagClass_APPLICATION_TAGS,
+		TagClass_CONTEXT_SPECIFIC_TAGS,
+	}
+}
+
+func TagClassByValue(value uint8) TagClass {
+	switch value {
+	case 0x0:
+		return TagClass_APPLICATION_TAGS
+	case 0x1:
+		return TagClass_CONTEXT_SPECIFIC_TAGS
+	}
+	return 0
+}
+
+func TagClassByName(value string) TagClass {
+	switch value {
+	case "APPLICATION_TAGS":
+		return TagClass_APPLICATION_TAGS
+	case "CONTEXT_SPECIFIC_TAGS":
+		return TagClass_CONTEXT_SPECIFIC_TAGS
+	}
+	return 0
+}
+
+func CastTagClass(structType interface{}) TagClass {
+	castFunc := func(typ interface{}) TagClass {
+		if sTagClass, ok := typ.(TagClass); ok {
+			return sTagClass
+		}
+		return 0
+	}
+	return castFunc(structType)
+}
+
+func (m TagClass) LengthInBits() uint16 {
+	return 1
+}
+
+func (m TagClass) LengthInBytes() uint16 {
+	return m.LengthInBits() / 8
+}
+
+func TagClassParse(readBuffer utils.ReadBuffer) (TagClass, error) {
+	val, err := readBuffer.ReadUint8("TagClass", 1)
+	if err != nil {
+		return 0, nil
+	}
+	return TagClassByValue(val), nil
+}
+
+func (e TagClass) Serialize(writeBuffer utils.WriteBuffer) error {
+	return writeBuffer.WriteUint8("TagClass", 1, uint8(e), utils.WithAdditionalStringRepresentation(e.name()))
+}
+
+func (e TagClass) name() string {
+	switch e {
+	case TagClass_APPLICATION_TAGS:
+		return "APPLICATION_TAGS"
+	case TagClass_CONTEXT_SPECIFIC_TAGS:
+		return "CONTEXT_SPECIFIC_TAGS"
+	}
+	return ""
+}
+
+func (e TagClass) String() string {
+	return e.name()
+}
diff --git a/plc4go/internal/plc4go/spi/default/DefaultCodec.go b/plc4go/internal/plc4go/spi/default/DefaultCodec.go
index 3a4f7f6..b1496e1 100644
--- a/plc4go/internal/plc4go/spi/default/DefaultCodec.go
+++ b/plc4go/internal/plc4go/spi/default/DefaultCodec.go
@@ -144,7 +144,7 @@ func (m *defaultCodec) Connect() error {
 	err := m.transportInstance.Connect()
 	if err == nil {
 		if !m.running {
-			log.Debug().Msg("Message codec currently not running")
+			log.Debug().Msg("Message codec currently not running, starting worker now")
 			go m.Work(&m.DefaultCodecRequirements)
 		}
 		m.running = true
diff --git a/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec b/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
index dff6c5c..e15bc26 100644
--- a/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
+++ b/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
@@ -302,16 +302,17 @@
         ['0x06' BACnetUnconfirmedServiceRequestTimeSynchronization
         ]
         ['0x07' BACnetUnconfirmedServiceRequestWhoHas
-            [const uint 8 'deviceInstanceLowLimitHeader' '0x0B']
-            [simple uint 24 'deviceInstanceLowLimit']
-            [const uint 8 'deviceInstanceHighLimitHeader' '0x1B']
-            [simple uint 24 'deviceInstanceHighLimit']
-            [const uint 8 'objectNameHeader' '0x3D']
-            [implicit uint 8 'objectNameLength' 'COUNT(objectName) + 1']
-            [simple uint 8 'objectNameCharacterSet']
-            [array int 8 'objectName' length 'objectNameLength - 1']
+            [const uint 8 'deviceInstanceLowLimitHeader' '0x0B'         ]
+            [simple uint 24 'deviceInstanceLowLimit'                    ]
+            [const uint 8 'deviceInstanceHighLimitHeader' '0x1B'        ]
+            [simple uint 24 'deviceInstanceHighLimit'                   ]
+            [const uint 8 'objectNameHeader' '0x3D'                     ]
+            [implicit uint 8 'objectNameLength' 'COUNT(objectName) + 1' ]
+            [simple uint 8 'objectNameCharacterSet'                     ]
+            [array int 8 'objectName' length 'objectNameLength - 1'     ]
         ]
         ['0x08' BACnetUnconfirmedServiceRequestWhoIs
+            // TODO: here we need proper bacnet tags (like a dicriminator etc... see line 494 BACnetTag)
             [const uint 5 'deviceInstanceRangeLowLimitHeader' '0x01']
             [simple uint 3 'deviceInstanceRangeLowLimitLength']
             [array int 8 'deviceInstanceRangeLowLimit' count 'deviceInstanceRangeLowLimitLength']
@@ -479,63 +480,72 @@
 ]
 
 [type 'BACnetTagWithContent'
-    [simple        uint 4 'typeOrTagNumber']
-    [simple        uint 1 'contextSpecificTag']
-    [simple        uint 3 'lengthValueType']
-    [optional      uint 8 'extTagNumber'        'typeOrTagNumber == 15']
-    [optional      uint 8 'extLength'           'lengthValueType == 5']
-    [array         uint 8 'propertyIdentifier'  length          '(lengthValueType == 5) ? extLength : lengthValueType']
-    [const         uint 8 'openTag'             '0x2e']
-    [simple        BACnetTag 'value']
-    [const         uint 8 'closingTag'          '0x2f']
+    [simple        uint 4    'tagNumber'       ]
+    [simple        TagClass  'tagClass'        ]
+    [simple        uint 3    'lengthValueType' ]
+    [optional      uint 8    'extTagNumber'        'tagNumber == 15'     ]
+    [optional      uint 8    'extLength'           'lengthValueType == 5']
+    [array         uint 8    'propertyIdentifier'  length          '(lengthValueType == 5) ? extLength : lengthValueType']
+    [const         uint 8    'openTag'             '0x2e']
+    [simple        BACnetTag 'value'                     ]
+    [const         uint 8    'closingTag'          '0x2f']
 ]
 
 [discriminatedType 'BACnetTag'
-    [simple        uint 4 'typeOrTagNumber']
-    [discriminator uint 1 'contextSpecificTag']
-    [simple        uint 3 'lengthValueType']
-    [optional      uint 8 'extTagNumber' 'typeOrTagNumber == 15']
-    [optional      uint 8 'extLength' 'lengthValueType == 5']
-    [typeSwitch 'contextSpecificTag','typeOrTagNumber'
-        ['0','0x0' BACnetTagApplicationNull
-        ]
-        ['0','0x1' BACnetTagApplicationBoolean
-        ]
-        ['0','0x2' BACnetTagApplicationUnsignedInteger [uint 3 'lengthValueType', uint 8 'extLength']
+    [simple        uint 4   'tagNumber'                                                  ]
+    [discriminator TagClass 'tagClass'                                                   ]
+    [simple        uint 3   'lengthValueType'                                            ]
+    [virtual       bit      'isPrimitiveAndNotBoolean' '!(tagClass == TagClass.CONTEXT_SPECIFIC_TAGS && lengthValueType == 6) && tagNumber != 1']
+    [optional      uint 8   'extTagNumber'    'isPrimitiveAndNotBoolean && tagNumber == 15'                          ]
+    [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 : (isPrimitiveAndNotBoolean ? lengthValueType : 0)))']
+    [typeSwitch 'tagClass','tagNumber'
+        ['APPLICATION_TAGS','0x0' BACnetTagApplicationNull
+        ]
+        ['APPLICATION_TAGS','0x1' BACnetTagApplicationBoolean
+        ]
+        ['APPLICATION_TAGS','0x2' BACnetTagApplicationUnsignedInteger [uint 3 'lengthValueType', uint 8 'extLength']
             [array int 8 'data' length '(lengthValueType == 5) ? extLength : lengthValueType']
         ]
-        ['0','0x3' BACnetTagApplicationSignedInteger [uint 3 'lengthValueType', uint 8 'extLength']
+        ['APPLICATION_TAGS','0x3' BACnetTagApplicationSignedInteger [uint 3 'lengthValueType', uint 8 'extLength']
             [array int 8 'data' length '(lengthValueType == 5) ? extLength : lengthValueType']
         ]
-        ['0','0x4' BACnetTagApplicationReal [uint 3 'lengthValueType', uint 8 'extLength']
+        ['APPLICATION_TAGS','0x4' BACnetTagApplicationReal [uint 3 'lengthValueType', uint 8 'extLength']
             [simple float 8.23 'value']
         ]
-        ['0','0x5' BACnetTagApplicationDouble [uint 3 'lengthValueType', uint 8 'extLength']
+        ['APPLICATION_TAGS','0x5' BACnetTagApplicationDouble [uint 3 'lengthValueType', uint 8 'extLength']
             [simple float 11.52 'value']
         ]
-        ['0','0x6' BACnetTagApplicationOctetString
+        ['APPLICATION_TAGS','0x6' BACnetTagApplicationOctetString
         ]
-        ['0','0x7' BACnetTagApplicationCharacterString
+        ['APPLICATION_TAGS','0x7' BACnetTagApplicationCharacterString
         ]
-        ['0','0x8' BACnetTagApplicationBitString [uint 3 'lengthValueType', uint 8 'extLength']
+        ['APPLICATION_TAGS','0x8' BACnetTagApplicationBitString [uint 3 'lengthValueType', uint 8 'extLength']
             [simple uint 8 'unusedBits']
             [array int 8 'data' length '(lengthValueType == 5) ? (extLength - 1) : (lengthValueType - 1)']
         ]
-        ['0','0x9' BACnetTagApplicationEnumerated [uint 3 'lengthValueType', uint 8 'extLength']
+        ['APPLICATION_TAGS','0x9' BACnetTagApplicationEnumerated [uint 3 'lengthValueType', uint 8 'extLength']
             [array int 8 'data' length '(lengthValueType == 5) ? extLength : lengthValueType']
         ]
-        ['0','0xA' BACnetTagApplicationDate
+        ['APPLICATION_TAGS','0xA' BACnetTagApplicationDate
         ]
-        ['0','0xB' BACnetTagApplicationTime
+        ['APPLICATION_TAGS','0xB' BACnetTagApplicationTime
         ]
-        ['0','0xC' BACnetTagApplicationObjectIdentifier
+        ['APPLICATION_TAGS','0xC' BACnetTagApplicationObjectIdentifier
         ]
-        ['1' BACnetTagContext [uint 4 'typeOrTagNumber', uint 8 'extTagNumber', uint 3 'lengthValueType', uint 8 'extLength']
+        ['CONTEXT_SPECIFIC_TAGS' BACnetTagContext [uint 4 'tagNumber', uint 8 'extTagNumber', uint 3 'lengthValueType', uint 8 'extLength']
             [array int 8 'data' length '(lengthValueType == 5) ? extLength : lengthValueType']
         ]
     ]
 ]
 
+[enum uint 1 'TagClass'
+    ['0x0' APPLICATION_TAGS]
+    ['0x1' CONTEXT_SPECIFIC_TAGS]
+]
+
 [enum int 4 'ApplicationTag'
     ['0x0' NULL]
     ['0x1' BOOLEAN]
diff --git a/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/protocol/BacNetIpProtocolLogic.java b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/protocol/BacNetIpProtocolLogic.java
index e4cdee1..cf9accb 100644
--- a/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/protocol/BacNetIpProtocolLogic.java
+++ b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/protocol/BacNetIpProtocolLogic.java
@@ -149,7 +149,7 @@ public class BacNetIpProtocolLogic extends Plc4xProtocolBase<BVLC> implements Ha
             long objectInstance = valueChange.getIssueConfirmedNotificationsInstanceNumber();
             BacNetIpField curField = new BacNetIpField(deviceIdentifier, objectType, objectInstance);
 
-            // The actual value change is in the notifications ... iterate throught them to get it.
+            // The actual value change is in the notifications ... iterate through them to get it.
             for (BACnetTagWithContent notification : valueChange.getNotifications()) {
                 // These are value change notifications. Ignore the rest.
                 if (notification.getPropertyIdentifier()[0] == (short) 0x55) {
@@ -163,13 +163,9 @@ public class BacNetIpProtocolLogic extends Plc4xProtocolBase<BVLC> implements Ha
                     enrichedPlcValue.put("address", new PlcSTRING(toString(curField)));
 
                     // From the original BACNet tag
-                    enrichedPlcValue.put("typeOrTagNumber", IEC61131ValueHandler.of(baCnetTag.getTypeOrTagNumber()));
+                    short tagNumber = baCnetTag.getTagNumber() < 0b1111 ? baCnetTag.getTagNumber() : baCnetTag.getExtTagNumber();
+                    enrichedPlcValue.put("tagNumber", IEC61131ValueHandler.of(tagNumber));
                     enrichedPlcValue.put("lengthValueType", IEC61131ValueHandler.of(baCnetTag.getLengthValueType()));
-                    if (baCnetTag.getExtTagNumber() != null) {
-                        enrichedPlcValue.put("extTagNumber", IEC61131ValueHandler.of(baCnetTag.getExtTagNumber()));
-                    } else {
-                        enrichedPlcValue.put("extTagNumber", new PlcNull());
-                    }
                     if (baCnetTag.getExtLength() != null) {
                         enrichedPlcValue.put("extLength", IEC61131ValueHandler.of(baCnetTag.getExtLength()));
                     } else {
@@ -245,7 +241,7 @@ public class BacNetIpProtocolLogic extends Plc4xProtocolBase<BVLC> implements Ha
     protected void publishEvent(BacNetIpField field, PlcValue plcValue) {
         // Create a subscription event from the input.
         final PlcSubscriptionEvent event = new DefaultPlcSubscriptionEvent(Instant.now(),
-            Collections.singletonMap("event", new ResponseItem(PlcResponseCode.OK, plcValue)));
+            Collections.singletonMap("event", new ResponseItem<>(PlcResponseCode.OK, plcValue)));
 
         // Send the subscription event to all listeners.
         for (Consumer<PlcSubscriptionEvent> consumer : consumerIdMap.values()) {
diff --git a/sandbox/test-java-bacnetip-driver/src/test/java/org/apache/plc4x/java/bacnetip/PassiveBacNetIpDriver2Manual.java b/sandbox/test-java-bacnetip-driver/src/test/java/org/apache/plc4x/java/bacnetip/PassiveBacNetIpDriver2Manual.java
new file mode 100644
index 0000000..a4cbae4
--- /dev/null
+++ b/sandbox/test-java-bacnetip-driver/src/test/java/org/apache/plc4x/java/bacnetip/PassiveBacNetIpDriver2Manual.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   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 org.apache.plc4x.java.bacnetip;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.plc4x.java.api.PlcConnection;
+import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse;
+import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionEvent;
+import org.apache.plc4x.java.spi.values.PlcStruct;
+
+import java.io.File;
+import java.net.URL;
+import java.nio.file.Path;
+
+public class PassiveBacNetIpDriver2Manual {
+
+    public static void main(String[] args) throws Exception {
+        String tempDirectory = FileUtils.getTempDirectoryPath();
+        File pcapFile = Path.of(tempDirectory, "bacnet-stack-services.cap").toFile();
+        if (!pcapFile.exists())
+            FileUtils.copyURLToFile(new URL("https://wiki.wireshark.org/Protocols/bacnet?action=AttachFile&do=get&target=bacnet-stack-services.cap"), pcapFile);
+
+
+        final BacNetIpDriver driver = new BacNetIpDriver();
+        final PlcConnection connection = driver.getConnection(
+            "bacnet-ip:pcap://" + pcapFile.getAbsolutePath());
+        connection.connect();
+        final PlcSubscriptionResponse subscriptionResponse = connection.subscriptionRequestBuilder().addEventField(
+            "Hurz", "*/*/*").build().execute().get();
+        subscriptionResponse.getSubscriptionHandle("Hurz").register(plcSubscriptionEvent -> {
+            PlcStruct plcStruct = (PlcStruct)
+                ((DefaultPlcSubscriptionEvent) plcSubscriptionEvent).getValues().get("event").getValue();
+            System.out.println(plcStruct);
+        });
+    }
+
+}