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 2024/10/07 15:44:54 UTC

(plc4x) branch develop updated: feat(plc4go/bacnetip): partial working LocalDeviceObject

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

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


The following commit(s) were added to refs/heads/develop by this push:
     new ab677e89d7 feat(plc4go/bacnetip): partial working LocalDeviceObject
ab677e89d7 is described below

commit ab677e89d72d9ca00088f1498ad2b965cdb5d933
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Mon Oct 7 17:44:41 2024 +0200

    feat(plc4go/bacnetip): partial working LocalDeviceObject
---
 .../bacgopes/basetypes/basetypes_AddressBinding.go |  10 +-
 .../basetypes/basetypes_AuditOperationFlags.go     |  16 +-
 .../basetypes/basetypes_COVMultipleSubscription.go |   8 +-
 .../basetypes_COVMultipleSubscriptionList.go       |  10 +-
 ...es_COVMultipleSubscriptionListOfCOVReference.go |  10 +-
 .../basetypes/basetypes_COVSubscription.go         |   8 +-
 .../basetypes_EventParameterChangeOfBitstring.go   |   2 +-
 .../basetypes/basetypes_EventTransitionBits.go     |  16 +-
 .../basetypes/basetypes_NameValueCollection.go     |   2 +-
 .../basetypes/basetypes_ObjectTypesSupported.go    |  17 +-
 .../bacgopes/basetypes/basetypes_Recipient.go      |  11 +-
 .../basetypes/basetypes_ServicesSupported.go       |  16 +-
 .../bacgopes/basetypes/basetypes_StatusFlags.go    |  17 +-
 .../bacgopes/basetypes/basetypes_TimeStamp.go      |   8 +-
 .../bacgopes/basetypes/basetypes_VTSession.go      |  10 +-
 .../bacnetip/bacgopes/comp/comp_KnownKeys.go       |   1 +
 .../bacgopes/constructeddata/constructeddata.go    | 199 +++++++++++-
 .../constructeddata/constructeddata_Choice.go      | 347 ++++++++++++++++++++-
 .../device/device.go}                              |  10 +-
 .../local/device/local_device_LocalDevice.go       | 200 +++++++++++-
 plc4go/internal/bacnetip/bacgopes/object/object.go | 144 +++++++--
 .../bacgopes/object/object_BitStringValueObject.go |   2 +-
 .../bacgopes/object/object_DeviceObject.go         |  17 +-
 .../bacgopes/object/object_ElevatorGroupObject.go  |   2 +-
 .../bacnetip/bacgopes/object/object_Object.go      |  12 +-
 .../bacnetip/bacgopes/object/object_Property.go    |  30 +-
 26 files changed, 1034 insertions(+), 91 deletions(-)

diff --git a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_AddressBinding.go b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_AddressBinding.go
index 88f6bb1efa..5a3adc3963 100644
--- a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_AddressBinding.go
+++ b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_AddressBinding.go
@@ -20,6 +20,8 @@
 package basetypes
 
 import (
+	"github.com/pkg/errors"
+
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/constructeddata"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
@@ -30,13 +32,17 @@ type AddressBinding struct {
 	sequenceElements []Element
 }
 
-func NewAddressBinding(arg Arg) (*AddressBinding, error) {
+func NewAddressBinding(_ Arg) (*AddressBinding, error) {
 	s := &AddressBinding{
 		sequenceElements: []Element{
 			NewElement("deviceObjectIdentifier", Vs2E(NewObjectIdentifier)),
 			NewElement("deviceAddress", V2E(NewDeviceAddress)),
 		},
 	}
-	panic("implementchoice")
+	var err error
+	s.Sequence, err = NewSequence(Nothing())
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating sequence")
+	}
 	return s, nil
 }
diff --git a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_AuditOperationFlags.go b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_AuditOperationFlags.go
index ff14f6acee..8a729a266d 100644
--- a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_AuditOperationFlags.go
+++ b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_AuditOperationFlags.go
@@ -20,6 +20,8 @@
 package basetypes
 
 import (
+	"github.com/pkg/errors"
+
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
 )
@@ -54,6 +56,18 @@ func NewAuditOperationFlags(arg Arg) (*AuditOperationFlags, error) {
 		},
 		bitLen: 16,
 	}
-	panic("implement me")
+	var err error
+	s.BitString, err = NewBitStringWithExtension(s, NA(arg))
+	if err != nil {
+		return nil, errors.Wrap(err, "NewBitStringWithExtension failed")
+	}
 	return s, nil
 }
+
+func (a AuditOperationFlags) GetBitNames() map[string]int {
+	return a.bitNames
+}
+
+func (a AuditOperationFlags) GetBitLen() int {
+	return a.bitLen
+}
diff --git a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVMultipleSubscription.go b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVMultipleSubscription.go
index b6b62a15fd..173f48f72a 100644
--- a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVMultipleSubscription.go
+++ b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVMultipleSubscription.go
@@ -20,6 +20,8 @@
 package basetypes
 
 import (
+	"github.com/pkg/errors"
+
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/constructeddata"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
@@ -40,6 +42,10 @@ func NewCOVMultipleSubscription(arg Arg) (*COVMultipleSubscription, error) {
 			NewElement("listOfCOVSubscriptionSpecifications", SequenceOfE(NewCOVMultipleSubscriptionList), WithElementContext(4)),
 		},
 	}
-	panic("implementchoice")
+	var err error
+	s.Sequence, err = NewSequence(Nothing())
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating sequence")
+	}
 	return s, nil
 }
diff --git a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVMultipleSubscriptionList.go b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVMultipleSubscriptionList.go
index 15d3788f55..a2f3cf36f4 100644
--- a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVMultipleSubscriptionList.go
+++ b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVMultipleSubscriptionList.go
@@ -20,6 +20,8 @@
 package basetypes
 
 import (
+	"github.com/pkg/errors"
+
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/constructeddata"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
@@ -30,13 +32,17 @@ type COVMultipleSubscriptionList struct {
 	sequenceElements []Element
 }
 
-func NewCOVMultipleSubscriptionList(arg Arg) (*COVMultipleSubscriptionList, error) {
+func NewCOVMultipleSubscriptionList(_ Arg) (*COVMultipleSubscriptionList, error) {
 	s := &COVMultipleSubscriptionList{
 		sequenceElements: []Element{
 			NewElement("monitoredObjectIdentifier", Vs2E(NewObjectIdentifier), WithElementContext(0)),
 			NewElement("listOfCOVReferences", SequenceOfE(NewCOVMultipleSubscriptionListOfCOVReference), WithElementContext(1)),
 		},
 	}
-	panic("implementchoice")
+	var err error
+	s.Sequence, err = NewSequence(Nothing())
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating sequence")
+	}
 	return s, nil
 }
diff --git a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVMultipleSubscriptionListOfCOVReference.go b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVMultipleSubscriptionListOfCOVReference.go
index 1a3c600e14..f653658196 100644
--- a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVMultipleSubscriptionListOfCOVReference.go
+++ b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVMultipleSubscriptionListOfCOVReference.go
@@ -20,6 +20,8 @@
 package basetypes
 
 import (
+	"github.com/pkg/errors"
+
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/constructeddata"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
@@ -30,7 +32,7 @@ type COVMultipleSubscriptionListOfCOVReference struct {
 	sequenceElements []Element
 }
 
-func NewCOVMultipleSubscriptionListOfCOVReference(arg Arg) (*COVMultipleSubscriptionListOfCOVReference, error) {
+func NewCOVMultipleSubscriptionListOfCOVReference(_ Arg) (*COVMultipleSubscriptionListOfCOVReference, error) {
 	s := &COVMultipleSubscriptionListOfCOVReference{
 		sequenceElements: []Element{
 			NewElement("monitoredProperty", V2E(NewPropertyReference), WithElementContext(0)),
@@ -38,6 +40,10 @@ func NewCOVMultipleSubscriptionListOfCOVReference(arg Arg) (*COVMultipleSubscrip
 			NewElement("timestamped", V2E(NewBoolean), WithElementContext(2)),
 		},
 	}
-	panic("implementchoice")
+	var err error
+	s.Sequence, err = NewSequence(Nothing())
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating sequence")
+	}
 	return s, nil
 }
diff --git a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVSubscription.go b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVSubscription.go
index 13419975f8..fad72da6a7 100644
--- a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVSubscription.go
+++ b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_COVSubscription.go
@@ -20,6 +20,8 @@
 package basetypes
 
 import (
+	"github.com/pkg/errors"
+
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/constructeddata"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
@@ -40,6 +42,10 @@ func NewCOVSubscription(arg Arg) (*COVSubscription, error) {
 			NewElement("covIncrement", V2E(NewReal), WithElementContext(4), WithElementOptional(true)),
 		},
 	}
-	panic("implementchoice")
+	var err error
+	s.Sequence, err = NewSequence(Nothing())
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating sequence")
+	}
 	return s, nil
 }
diff --git a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_EventParameterChangeOfBitstring.go b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_EventParameterChangeOfBitstring.go
index b96b12e5db..c82638982d 100644
--- a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_EventParameterChangeOfBitstring.go
+++ b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_EventParameterChangeOfBitstring.go
@@ -35,7 +35,7 @@ func NewEventParameterChangeOfBitstring(arg Arg) (*EventParameterChangeOfBitstri
 		sequenceElements: []Element{
 			NewElement("timeDelay", V2E(NewUnsigned), WithElementContext(0)),
 			NewElement("bitmask", Vs2E(NewBitString), WithElementContext(1)),
-			NewElement("listOfBitstringValues", SequenceOfsE(NewBitString), WithElementContext(2)),
+			NewElement("listOfBitstringValues", SequenceOfEs(NewBitString), WithElementContext(2)),
 		},
 	}
 	panic("implementchoice")
diff --git a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_EventTransitionBits.go b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_EventTransitionBits.go
index 899477355d..c0daeb1d84 100644
--- a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_EventTransitionBits.go
+++ b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_EventTransitionBits.go
@@ -20,6 +20,8 @@
 package basetypes
 
 import (
+	"github.com/pkg/errors"
+
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
 )
@@ -40,6 +42,18 @@ func NewEventTransitionBits(arg Arg) (*EventTransitionBits, error) {
 		},
 		bitLen: 3,
 	}
-	panic("implement me")
+	var err error
+	s.BitString, err = NewBitStringWithExtension(s, NA(arg))
+	if err != nil {
+		return nil, errors.Wrap(err, "NewBitStringWithExtension failed")
+	}
 	return s, nil
 }
+
+func (e EventTransitionBits) GetBitNames() map[string]int {
+	return e.bitNames
+}
+
+func (e EventTransitionBits) GetBitLen() int {
+	return e.bitLen
+}
diff --git a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_NameValueCollection.go b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_NameValueCollection.go
index 36d6496e92..21a3537e24 100644
--- a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_NameValueCollection.go
+++ b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_NameValueCollection.go
@@ -32,7 +32,7 @@ type NameValueCollection struct {
 func NewNameValueCollection(arg Arg) (*NameValueCollection, error) {
 	s := &NameValueCollection{
 		sequenceElements: []Element{
-			NewElement("members", SequenceOfsE(NewNameValue), WithElementContext(0)),
+			NewElement("members", SequenceOfEs(NewNameValue), WithElementContext(0)),
 		},
 	}
 	panic("implementchoice")
diff --git a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_ObjectTypesSupported.go b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_ObjectTypesSupported.go
index be1fe7e84d..5110c84b8f 100644
--- a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_ObjectTypesSupported.go
+++ b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_ObjectTypesSupported.go
@@ -20,6 +20,8 @@
 package basetypes
 
 import (
+	"github.com/pkg/errors"
+
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
 )
@@ -99,6 +101,19 @@ func NewObjectTypesSupported(arg Arg) (*ObjectTypesSupported, error) {
 		},
 		bitLen: 63,
 	}
-	panic("implement me")
+
+	var err error
+	s.BitString, err = NewBitStringWithExtension(s, NA(arg))
+	if err != nil {
+		return nil, errors.Wrap(err, "NewBitStringWithExtension failed")
+	}
 	return s, nil
 }
+
+func (o ObjectTypesSupported) GetBitNames() map[string]int {
+	return o.bitNames
+}
+
+func (o ObjectTypesSupported) GetBitLen() int {
+	return o.bitLen
+}
diff --git a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_Recipient.go b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_Recipient.go
index 7e56dfb646..5655e55ecb 100644
--- a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_Recipient.go
+++ b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_Recipient.go
@@ -20,6 +20,8 @@
 package basetypes
 
 import (
+	"github.com/pkg/errors"
+
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/constructeddata"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
@@ -30,13 +32,18 @@ type Recipient struct {
 	choiceElements []Element
 }
 
-func NewRecipient(arg Arg) (*Recipient, error) {
+func NewRecipient(_ Arg) (*Recipient, error) {
 	s := &Recipient{
 		choiceElements: []Element{
 			NewElement("device", Vs2E(NewObjectIdentifier), WithElementContext(0)),
 			NewElement("address", V2E(NewDeviceAddress), WithElementContext(1)),
 		},
 	}
-	panic("implementchoice")
+
+	var err error
+	s.Choice, err = NewChoice(Nothing())
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating choice")
+	}
 	return s, nil
 }
diff --git a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_ServicesSupported.go b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_ServicesSupported.go
index 350c1447fa..3c1503dd18 100644
--- a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_ServicesSupported.go
+++ b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_ServicesSupported.go
@@ -20,6 +20,8 @@
 package basetypes
 
 import (
+	"github.com/pkg/errors"
+
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
 )
@@ -86,6 +88,18 @@ func NewServicesSupported(arg Arg) (*ServicesSupported, error) {
 		},
 		bitLen: 49,
 	}
-	panic("implement me")
+	var err error
+	s.BitString, err = NewBitStringWithExtension(s, NA(arg))
+	if err != nil {
+		return nil, errors.Wrap(err, "NewBitStringWithExtension failed")
+	}
 	return s, nil
 }
+
+func (s ServicesSupported) GetBitNames() map[string]int {
+	return s.bitNames
+}
+
+func (s ServicesSupported) GetBitLen() int {
+	return s.bitLen
+}
diff --git a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_StatusFlags.go b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_StatusFlags.go
index 1d0b9ffd83..203c3ae9e0 100644
--- a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_StatusFlags.go
+++ b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_StatusFlags.go
@@ -20,6 +20,8 @@
 package basetypes
 
 import (
+	"github.com/pkg/errors"
+
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
 )
@@ -41,6 +43,19 @@ func NewStatusFlags(arg Arg) (*StatusFlags, error) {
 		},
 		bitLen: 4,
 	}
-	panic("implement me")
+
+	var err error
+	s.BitString, err = NewBitStringWithExtension(s, NA(arg))
+	if err != nil {
+		return nil, errors.Wrap(err, "NewBitStringWithExtension failed")
+	}
 	return s, nil
 }
+
+func (s StatusFlags) GetBitNames() map[string]int {
+	return s.bitNames
+}
+
+func (s StatusFlags) GetBitLen() int {
+	return s.bitLen
+}
diff --git a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_TimeStamp.go b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_TimeStamp.go
index 7d25afbc56..3fdb263ce1 100644
--- a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_TimeStamp.go
+++ b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_TimeStamp.go
@@ -20,6 +20,8 @@
 package basetypes
 
 import (
+	"github.com/pkg/errors"
+
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/constructeddata"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
@@ -38,6 +40,10 @@ func NewTimeStamp(arg Arg) (*TimeStamp, error) {
 			NewElement("dateTime", V2E(NewDateTime), WithElementContext(2)),
 		},
 	}
-	panic("implementchoice")
+	var err error
+	s.Choice, err = NewChoice(Nothing())
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating choice")
+	}
 	return s, nil
 }
diff --git a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_VTSession.go b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_VTSession.go
index 8c1393e2ee..586e200c70 100644
--- a/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_VTSession.go
+++ b/plc4go/internal/bacnetip/bacgopes/basetypes/basetypes_VTSession.go
@@ -20,6 +20,8 @@
 package basetypes
 
 import (
+	"github.com/pkg/errors"
+
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/constructeddata"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
@@ -30,7 +32,7 @@ type VTSession struct {
 	sequenceElements []Element
 }
 
-func NewVTSession(arg Arg) (*VTSession, error) {
+func NewVTSession(_ Arg) (*VTSession, error) {
 	s := &VTSession{
 		sequenceElements: []Element{
 			NewElement("localVtSessionID", V2E(NewUnsigned)),
@@ -38,6 +40,10 @@ func NewVTSession(arg Arg) (*VTSession, error) {
 			NewElement("remoteVtAddress", V2E(NewDeviceAddress)),
 		},
 	}
-	panic("implementchoice")
+	var err error
+	s.Sequence, err = NewSequence(Nothing())
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating sequence")
+	}
 	return s, nil
 }
diff --git a/plc4go/internal/bacnetip/bacgopes/comp/comp_KnownKeys.go b/plc4go/internal/bacnetip/bacgopes/comp/comp_KnownKeys.go
index 12f740c8af..7f29f085a9 100644
--- a/plc4go/internal/bacnetip/bacgopes/comp/comp_KnownKeys.go
+++ b/plc4go/internal/bacnetip/bacgopes/comp/comp_KnownKeys.go
@@ -92,4 +92,5 @@ const (
 	KWMaxSegmentsAccepted       = KnownKey("segmentsAccepted")
 	KWNumberOfAPDURetries       = KnownKey("numberOfAPDURetries")
 	KWVendorIdentifier          = KnownKey("vendorIdentifier")
+	KWCls                       = KnownKey("cls")
 )
diff --git a/plc4go/internal/bacnetip/bacgopes/constructeddata/constructeddata.go b/plc4go/internal/bacnetip/bacgopes/constructeddata/constructeddata.go
index 1d3ba03321..b4deb4ed68 100644
--- a/plc4go/internal/bacnetip/bacgopes/constructeddata/constructeddata.go
+++ b/plc4go/internal/bacnetip/bacgopes/constructeddata/constructeddata.go
@@ -20,19 +20,24 @@
 package constructeddata
 
 import (
+	"fmt"
+
+	"github.com/pkg/errors"
+
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/debugging"
+	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
+	readWriteModel "github.com/apache/plc4x/plc4go/protocols/bacnetip/readwrite/model"
 )
 
 var _debug = CreateDebugPrinter()
 
-var _sequenceOfClasses map[any]struct{}
-var _listOfClasses map[any]struct{}
-
-func init() {
-	_sequenceOfClasses = make(map[any]struct{})
-	_listOfClasses = make(map[any]struct{})
-}
+var _arrayOfMap = make(map[any]func(Args, KWArgs) (ElementKlass, error))
+var _listOfMap = make(map[any]func(Args, KWArgs) (ElementKlass, error))
+var _sequenceOfMap = make(map[any]func(Args, KWArgs) (ElementKlass, error))
+var _sequenceOfClasses = make(map[any]struct{})
+var _arrayOfClasses = make(map[any]struct{})
+var _listOfClasses = make(map[any]struct{})
 
 // V2E accepts a function which takes an Arg and maps it to a ElementKlass
 func V2E[T any](b func(arg Arg) (*T, error)) func(Args, KWArgs) (ElementKlass, error) {
@@ -54,23 +59,183 @@ func Vs2E[T any](b func(args Args) (*T, error)) func(Args, KWArgs) (ElementKlass
 	}
 }
 
-// TODO: finish
-func SequenceOfE[T any](b func(arg Arg) (*T, error)) func(Args, KWArgs) (ElementKlass, error) {
-	panic("finish me")
+// TODO: big WIP
+type _SequenceOf[T any] struct {
+	name    string
+	subType func(Args) (*T, error)
 }
 
-func SequenceOfsE[T any](b func(args Args) (*T, error)) func(Args, KWArgs) (ElementKlass, error) {
-	panic("finish me")
+func (a _SequenceOf[T]) Encode(arg Arg) (O error) {
+	panic("implement me")
 }
 
-// TODO: finish // convert to kwArgs and check wtf we are doing here...
-func ArrayOfE[T any](b func(arg Arg) (*T, error), fixedLength int, prototype any) func(Args, KWArgs) (ElementKlass, error) {
-	panic("finish me")
+func (a _SequenceOf[T]) GetAppTag() readWriteModel.BACnetDataType {
+	panic("implement me")
+}
+
+func SequenceOfE[T any](klass func(arg Arg) (*T, error)) func(Args, KWArgs) (ElementKlass, error) {
+	return SequenceOfEs(func(args Args) (*T, error) {
+		if len(args) == 0 {
+			return klass(NoArgs)
+		}
+		if len(args) > 1 {
+			panic(fmt.Sprintf("oh no %d", len(args)))
+		}
+		return klass(args[0])
+	})
+}
+
+func SequenceOfEs[T any](klass func(args Args) (*T, error)) func(Args, KWArgs) (ElementKlass, error) {
+	elementKlass, err := klass(NoArgs)
+	if err != nil {
+		return func(_ Args, _ KWArgs) (ElementKlass, error) {
+			return nil, errors.Wrap(err, "can't get zero object")
+		}
+	}
+	switch any(elementKlass).(type) {
+	case IsAtomic:
+	// TODO: add prototype check...
+	default:
+		// TODO: add check
+	}
+
+	// if this has already been built, return the cached one
+	if v, ok := _sequenceOfMap[fmt.Sprintf("%T", elementKlass)]; ok {
+		return v
+	}
+
+	// no SequenceOf(SequenceOf(...)) allowed
+	if _, ok := _sequenceOfClasses[fmt.Sprintf("%T", elementKlass)]; ok {
+		return func(_ Args, _ KWArgs) (ElementKlass, error) {
+			return nil, errors.New("nested sequences disallowed")
+		}
+	}
+	// no SequenceOf(Array(...)) allowed
+	if _, ok := _arrayOfClasses[fmt.Sprintf("%T", elementKlass)]; ok {
+		return func(_ Args, _ KWArgs) (ElementKlass, error) {
+			return nil, errors.New("sequence of ArrayOf disallowed")
+		}
+	}
+
+	// define a generic class for arrays
+	_sequenceOf := struct {
+		*_SequenceOf[T]
+	}{&_SequenceOf[T]{}}
+
+	// constrain it to a list of a specific type of item
+	_sequenceOf.subType = klass
+
+	// update the name
+	_sequenceOf.name = "SequenceOf" + fmt.Sprintf("%T", elementKlass)
+
+	// cache this type
+	_sequenceOfMap[fmt.Sprintf("%T", elementKlass)] = func(_ Args, _ KWArgs) (ElementKlass, error) {
+		return _sequenceOf, nil
+	}
+	_sequenceOfClasses[fmt.Sprintf("%T", _sequenceOf)] = struct{}{}
+
+	return func(args Args, kwArgs KWArgs) (ElementKlass, error) {
+		return _sequenceOf, nil
+	}
+}
+
+// TODO: big WIP
+type _ArrayOf[T any] struct {
+	name        string
+	subType     func(Args) (*T, error)
+	fixedLength int
+	prototype   any
+}
+
+var _ ElementKlass = (*_ArrayOf[any])(nil)
+
+func (a *_ArrayOf[T]) GetAppTag() readWriteModel.BACnetDataType {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (a *_ArrayOf[T]) Encode(arg Arg) (O error) {
+	panic("implement me")
+}
+
+func ArrayOfE[T any](klass func(arg Arg) (*T, error), fixedLength int, prototype any) func(Args, KWArgs) (ElementKlass, error) {
+	return ArrayOfEs(func(args Args) (*T, error) {
+		if len(args) == 0 {
+			return klass(NoArgs)
+		}
+		if len(args) > 1 {
+			panic(fmt.Sprintf("oh no %d", len(args)))
+		}
+		return klass(args[0])
+	}, fixedLength, prototype)
 }
 
 // TODO: finish // convert to kwArgs and check wtf we are doing here...
-func ArrayOfsE[T any](b func(args Args) (*T, error), fixedLength int, prototype any) func(Args, KWArgs) (ElementKlass, error) {
-	panic("finish me")
+func ArrayOfEs[T any](klass func(args Args) (*T, error), fixedLength int, prototype any) func(Args, KWArgs) (ElementKlass, error) {
+	elementKlass, err := klass(NoArgs)
+	if err != nil {
+		return func(_ Args, _ KWArgs) (ElementKlass, error) {
+			return nil, errors.Wrap(err, "can't get zero object")
+		}
+	}
+	switch any(elementKlass).(type) {
+	case IsAtomic:
+	// TODO: add prototype check...
+	default:
+		// TODO: add check
+	}
+
+	// build a signature of the parameters
+	arraySignature := struct {
+		string
+		int
+		any
+	}{
+		fmt.Sprintf("%T", elementKlass),
+		fixedLength,
+		prototype,
+	}
+
+	// if this has already been built, return the cached one
+	if v, ok := _arrayOfMap[arraySignature]; ok {
+		return v
+	}
+
+	// no ArrayOf(ArrayOf(...)) allowed
+	if _, ok := _arrayOfClasses[fmt.Sprintf("%T", elementKlass)]; ok {
+		return func(_ Args, _ KWArgs) (ElementKlass, error) {
+			return nil, errors.New("nested arrays disallowed")
+		}
+	}
+	// no ArrayOf(SequenceOf(...)) allowed
+	if _, ok := _sequenceOfClasses[fmt.Sprintf("%T", elementKlass)]; ok {
+		return func(_ Args, _ KWArgs) (ElementKlass, error) {
+			return nil, errors.New("arrays of SequenceOf disallowed")
+		}
+	}
+
+	// define a generic class for arrays
+	_arrayOf := struct {
+		*_ArrayOf[T]
+	}{&_ArrayOf[T]{}}
+
+	// constrain it to a list of a specific type of item
+	_arrayOf.subType = klass
+	_arrayOf.fixedLength = fixedLength
+	_arrayOf.prototype = prototype
+
+	// update the name
+	_arrayOf.name = "ArrayOf" + fmt.Sprintf("%T", elementKlass)
+
+	// cache this type
+	_arrayOfMap[arraySignature] = func(_ Args, _ KWArgs) (ElementKlass, error) {
+		return _arrayOf, nil
+	}
+	_arrayOfClasses[fmt.Sprintf("%T", _arrayOf)] = struct{}{}
+
+	return func(args Args, kwArgs KWArgs) (ElementKlass, error) {
+		return _arrayOf, nil
+	}
 }
 
 // TODO: finish // convert to kwArgs and check wtf we are doing here...
diff --git a/plc4go/internal/bacnetip/bacgopes/constructeddata/constructeddata_Choice.go b/plc4go/internal/bacnetip/bacgopes/constructeddata/constructeddata_Choice.go
index 7c84560a75..2275ccedbf 100644
--- a/plc4go/internal/bacnetip/bacgopes/constructeddata/constructeddata_Choice.go
+++ b/plc4go/internal/bacnetip/bacgopes/constructeddata/constructeddata_Choice.go
@@ -19,6 +19,351 @@
 
 package constructeddata
 
-// TODO: finish
+import (
+	"fmt"
+	"io"
+	"reflect"
+	"strings"
+
+	"github.com/pkg/errors"
+
+	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
+	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/debugging"
+	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
+	readWriteModel "github.com/apache/plc4x/plc4go/protocols/bacnetip/readwrite/model"
+)
+
+// ChoiceContract provides a set of functions which can be overwritten by a sub struct
+type ChoiceContract interface {
+	GetChoiceElements() []Element
+}
+
+// ChoiceContractRequirement is needed when one want to extend using ChoiceContract
+type ChoiceContractRequirement interface {
+	ChoiceContract
+	// SetChoice callback is needed as we work in the constructor already with the finished object // TODO: maybe we need to return as init again as it might not be finished constructing....
+	SetChoice(s *Choice)
+}
+
 type Choice struct {
+	_contract      ChoiceContract
+	choiceElements []Element
+	attr           map[string]any
+}
+
+func NewChoice(args Args, kwArgs KWArgs, options ...Option) (*Choice, error) {
+	c := new(Choice)
+	ApplyAppliers(options, c)
+	if c._contract == nil {
+		c._contract = c
+	} else {
+		c._contract.(ChoiceContractRequirement).SetChoice(c)
+	}
+	if _debug != nil {
+		_debug("__init__ %r %r", args, kwArgs)
+	}
+
+	var myKWArgs = make(KWArgs)
+	var otherKWArgs = make(KWArgs)
+	for _, element := range c._contract.GetChoiceElements() {
+		if a, ok := kwArgs[KnownKey(element.GetName())]; ok {
+			myKWArgs[KnownKey(element.GetName())] = a
+		}
+	}
+	for key, a := range kwArgs {
+		if _, ok := myKWArgs[key]; !ok {
+			otherKWArgs[key] = a
+		}
+	}
+
+	if _debug != nil {
+		_debug("    - my_kwargs: %r", myKWArgs)
+	}
+	if _debug != nil {
+		_debug("    - other_kwargs: %r", otherKWArgs)
+	}
+
+	// set the attribute/property values for the ones provided
+	for _, element := range c._contract.GetChoiceElements() {
+		a, ok := myKWArgs[KnownKey(element.GetName())]
+		if ok {
+			c.attr[element.GetName()] = a
+		}
+	}
+	return c, nil
+}
+
+func WithChoiceExtension(contract ChoiceContractRequirement) GenericApplier[*Choice] {
+	return WrapGenericApplier(func(s *Choice) { s._contract = contract })
+}
+
+func (c *Choice) GetChoiceElements() []Element {
+	return c.choiceElements
+}
+
+func (c *Choice) GetAttr(key string) (any, bool) {
+	v, ok := c.attr[key]
+	return v, ok
+}
+
+func (c *Choice) Encode(arg Arg) error {
+	tagList, ok := arg.(*TagList)
+	if !ok {
+		return errors.New("arg is not a TagList")
+	}
+	if _debug != nil {
+		_debug("encode %r", tagList)
+	}
+
+	for _, element := range c._contract.GetChoiceElements() {
+		value, ok := c.attr[element.GetName()]
+		if element.IsOptional() && !ok {
+			continue
+		}
+		if !element.IsOptional() && !ok {
+			return errors.Errorf("%s is a missing required element of %T", element.GetName(), c)
+		}
+		elementKlass, err := element.GetKlass()(Nothing())
+		if err != nil {
+			return errors.Wrap(err, "can't get zero object")
+		}
+		_, elementInSequenceOfClasses := _sequenceOfClasses[fmt.Sprintf("%T", elementKlass)]
+		_, elementInListOfClasses := _listOfClasses[fmt.Sprintf("%T", elementKlass)]
+		isAtomic := false
+		switch elementKlass.(type) {
+		case IsAtomic, IsAnyAtomic:
+			isAtomic = true
+		}
+		isValue := reflect.TypeOf(value) == reflect.TypeOf(elementKlass)
+
+		if elementInSequenceOfClasses || elementInListOfClasses {
+			// might need to encode an opening tag
+			if element.GetContext() != nil {
+				openingTag, err := NewOpeningTag(*element.GetContext())
+				if err != nil {
+					return errors.Wrap(err, "error creating opening tag")
+				}
+				tagList.Append(openingTag)
+			}
+
+			helper, err := element.GetKlass()(NA(value), NoKWArgs())
+			if err != nil {
+				return errors.Wrap(err, "error klass element")
+			}
+
+			// encode the value
+			if err := helper.Encode(tagList); err != nil {
+				return errors.Wrap(err, "error encoding tag list")
+			}
+
+			// might need to encode a closing tag
+			if element.GetContext() != nil {
+				closingTag, err := NewClosingTag(*element.GetContext())
+				if err != nil {
+					return errors.Wrap(err, "error creating closing tag")
+				}
+				tagList.Append(closingTag)
+			}
+		} else if isAtomic {
+			helper, err := element.GetKlass()(NA(value), NoKWArgs())
+			if err != nil {
+				return errors.Wrap(err, "error klass element")
+			}
+
+			// build a tag and encode the data into it
+			tag, err := NewTag(nil)
+			if err != nil {
+				return errors.Wrap(err, "error creating tag")
+			}
+			// encode the value
+			if err := helper.Encode(tag); err != nil {
+				return errors.Wrap(err, "error encoding tag list")
+			}
+
+			// convert it to context encoding if necessary
+			if element.GetContext() != nil {
+				tag, err = tag.AppToContext(uint(*element.GetContext()))
+				if err != nil {
+					return errors.Wrap(err, "error converting tag to context")
+				}
+			}
+			tagList.Append(tag)
+		} else if isValue {
+			// might need to encode an opening tag
+			if element.GetContext() != nil {
+				openingTag, err := NewOpeningTag(*element.GetContext())
+				if err != nil {
+					return errors.Wrap(err, "error creating opening tag")
+				}
+				tagList.Append(openingTag)
+			}
+
+			// encode the tag
+			if err := value.(interface{ Encode(Arg) error }).Encode(tagList); err != nil { // TODO: ugly case, need a encode interface soon
+				return errors.Wrap(err, "error encoding tag list")
+			}
+
+			// might need to encode a closing tag
+			if element.GetContext() != nil {
+				closingTag, err := NewClosingTag(*element.GetContext())
+				if err != nil {
+					return errors.Wrap(err, "error creating closing tag")
+				}
+				tagList.Append(closingTag)
+			}
+		}
+	}
+	return nil
+}
+
+func (c *Choice) Decode(arg Arg) error {
+	tagList, ok := arg.(*TagList)
+	if !ok {
+		return errors.New("arg is not a TagList")
+	}
+	if _debug != nil {
+		_debug("decode %r", tagList)
+	}
+
+	for _, element := range c._contract.GetChoiceElements() {
+		tag := tagList.Peek()
+		if _debug != nil {
+			_debug("    - element, tag: %r, %r", element, tag)
+		}
+
+		elementKlass, err := element.GetKlass()(Nothing())
+		if err != nil {
+			return errors.Wrap(err, "can't get zero object")
+		}
+		_, elementInSequenceOfClasses := _sequenceOfClasses[elementKlass]
+		_, elementInListOfClasses := _listOfClasses[elementKlass]
+		isAtomic := false
+		isAnyAtomic := false
+		switch elementKlass.(type) {
+		case IsAtomic:
+			isAtomic = true
+		case IsAnyAtomic:
+			isAnyAtomic = true
+		}
+		// no more elements
+		if tag == nil {
+			if element.IsOptional() {
+				// ommited optional element
+				c.attr[element.GetName()] = nil
+			} else if elementInSequenceOfClasses || elementInListOfClasses {
+				// empty list
+				//a.attr[element.GetName()] = nil // TODO: what to do???
+			} else {
+				return errors.Errorf("%s is a missing required element of %T", element.GetName(), c)
+			}
+		} else if tag.GetTagClass() == TagClosingTagClass {
+			if !element.IsOptional() {
+				return errors.Errorf("%s is a missing required element of %T", element.GetName(), c)
+			}
+
+			// ommited optional element
+			// a.attr[element.GetName()] = nil // TODO: don't set it for now as we use _,ok:=
+		} else if elementInSequenceOfClasses {
+			// check for context encoding
+			panic("finish me") // TODO: finish me
+		} else if isAnyAtomic {
+			// convert it to application encoding
+			panic("finish me") // TODO: finish me
+		} else if isAtomic {
+			// convert it to application encoding
+			if context := element.GetContext(); context != nil {
+				if tag.GetTagClass() != readWriteModel.TagClass_CONTEXT_SPECIFIC_TAGS && tag.GetTagNumber() != uint(*context) {
+					if !element.IsOptional() {
+						return errors.Errorf("%s expected context tag %d", element.GetName(), *context)
+					} else {
+						// TODO: we don't do this
+						//a.attr[element.GetName()] = nil
+						continue
+					}
+				}
+				atomicTag := tag.(interface {
+					GetAppTag() readWriteModel.BACnetDataType
+				})
+				tag, err = tag.ContextToApp(uint(atomicTag.GetAppTag()))
+				if err != nil {
+					return errors.Wrap(err, "error converting tag")
+				}
+			} else {
+				if tag.GetTagClass() != readWriteModel.TagClass_APPLICATION_TAGS || tag.GetTagNumber() != uint(elementKlass.GetAppTag()) {
+					if !element.IsOptional() {
+						return errors.Errorf("%s expected context tag %d", element.GetName(), context)
+					} else {
+						// TODO: we don't do this
+						//a.attr[element.GetName()] = nil
+						continue
+					}
+				}
+			}
+
+			// consume the tag
+			tagList.Pop()
+
+			// a helper cooperates between the atomic value and the tag
+			helper, err := element.GetKlass()(NA(tag), NoKWArgs())
+			if err != nil {
+				return errors.Wrap(err, "error creating helper")
+			}
+			c.attr[element.GetName()] = helper
+		} else if isAnyAtomic { // TODO: what is upstream doing here??? how???
+			// convert it to application encoding
+			panic("finish me") // TODO: finish me
+		} else {
+			panic("finish me") // TODO: finish me
+		}
+	}
+	return nil
+}
+
+func (c *Choice) PrintDebugContents(indent int, file io.Writer, _ids []uintptr) {
+	for _, element := range c.choiceElements {
+		value, ok := c.GetAttr(element.GetName())
+		if element.IsOptional() && !ok {
+			continue
+		} else if !element.IsOptional() && !ok {
+			_, _ = fmt.Fprintf(file, "%s%s is a missing required element of %s\n", strings.Repeat("    ", indent), element.GetName(), StructName())
+			continue
+		}
+
+		elementKlass, err := element.GetKlass()(Nothing())
+		if err != nil {
+			if _debug != nil {
+				_debug("can't get zero object. %w", err)
+			}
+			return
+		}
+		_, elementInSequenceOfClasses := _sequenceOfClasses[elementKlass]
+		_, elementInListOfClasses := _listOfClasses[elementKlass]
+		isAtomic := false
+		isAnyAtomic := false
+		switch elementKlass.(type) {
+		case IsAtomic:
+			isAtomic = true
+		case IsAnyAtomic:
+			isAnyAtomic = true
+		}
+		isValueSubOfElementKlass := false // TODO: how to figure that out??
+		if elementInSequenceOfClasses || elementInListOfClasses {
+			_, _ = fmt.Fprintf(file, "%s%s\n", strings.Repeat("    ", indent), element.GetName())
+			helper, err := element.GetKlass()(NA(value), NoKWArgs())
+			if err != nil {
+				if _debug != nil {
+					_debug("    - helper class %s, err: %v", element.GetName(), err)
+				}
+				return
+			}
+			helper.(DebugContentPrinter).PrintDebugContents(indent+1, file, _ids)
+		} else if isAtomic || isAnyAtomic {
+			printVerb := VerbForType(value, 'r')
+			_, _ = fmt.Fprintf(file, "%s%s = "+string(printVerb)+"\n", strings.Repeat("    ", indent), element.GetName(), value)
+		} else if isValueSubOfElementKlass {
+			value.(DebugContentPrinter).PrintDebugContents(indent+1, file, _ids)
+		} else {
+			_, _ = fmt.Fprintf(file, "%s%s must be a %T\n", strings.Repeat("    ", indent), element.GetName(), element.GetKlass())
+		}
+	}
 }
diff --git a/plc4go/internal/bacnetip/bacgopes/constructeddata/constructeddata_Choice.go b/plc4go/internal/bacnetip/bacgopes/local/device/device.go
similarity index 85%
copy from plc4go/internal/bacnetip/bacgopes/constructeddata/constructeddata_Choice.go
copy to plc4go/internal/bacnetip/bacgopes/local/device/device.go
index 7c84560a75..5d63ed2c09 100644
--- a/plc4go/internal/bacnetip/bacgopes/constructeddata/constructeddata_Choice.go
+++ b/plc4go/internal/bacnetip/bacgopes/local/device/device.go
@@ -17,8 +17,10 @@
  * under the License.
  */
 
-package constructeddata
+package device
 
-// TODO: finish
-type Choice struct {
-}
+import (
+	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/debugging"
+)
+
+var _debug = CreateDebugPrinter()
diff --git a/plc4go/internal/bacnetip/bacgopes/local/device/local_device_LocalDevice.go b/plc4go/internal/bacnetip/bacgopes/local/device/local_device_LocalDevice.go
index f6ba59c869..b5427c5719 100644
--- a/plc4go/internal/bacnetip/bacgopes/local/device/local_device_LocalDevice.go
+++ b/plc4go/internal/bacnetip/bacgopes/local/device/local_device_LocalDevice.go
@@ -21,13 +21,17 @@ package device
 
 import (
 	"fmt"
+	"io"
+	"strings"
 
 	"github.com/pkg/errors"
 
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
+	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/constructeddata"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/debugging"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/local/object"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/object"
+	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
 	readWriteModel "github.com/apache/plc4x/plc4go/protocols/bacnetip/readwrite/model"
 )
 
@@ -48,18 +52,10 @@ type LocalDeviceObject interface {
 	SetObjectList([]string)
 }
 
-type _LocalDeviceObject struct {
-	*CurrentPropertyListMixIn
-	*DeviceObject
-	*DefaultRFormatter
-
-	properties        []Property
-	defaultProperties map[string]any
-
-	App any `ignore:"true"` // TODO: is *Application but creates a circular dependency. figure out what is a smart way
-}
-
-func NewLocalDeviceObject(args Args, kwArgs KWArgs, options ...Option) (LocalDeviceObject, error) {
+func NewLocalDeviceObject(_ Args, kwArgs KWArgs, options ...Option) (LocalDeviceObject, error) {
+	if _debug != nil {
+		_debug("__init__ %r", kwArgs)
+	}
 	l := &_LocalDeviceObject{
 		DefaultRFormatter: NewDefaultRFormatter(),
 		properties: []Property{
@@ -82,9 +78,144 @@ func NewLocalDeviceObject(args Args, kwArgs KWArgs, options ...Option) (LocalDev
 	if err != nil {
 		return nil, errors.Wrap(err, "error creating mixing")
 	}
+	l.DeviceObject, err = NewDeviceObject(nil)
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating device object")
+	}
+
+	// start with an empty dictionary of device object properties
+	initArgs := make(KWArgs)
+	iniArg, _ := KWO[KWArgs](kwArgs, "ini", nil)
+	if _debug != nil {
+		_debug("    - ini_arg: %r", iniArg)
+	}
+
+	if _, ok := RegisteredObjectTypes[fmt.Sprintf("%T", l)]; !ok {
+		if _debug != nil {
+			_debug("    - unregistered", kwArgs)
+		}
+		vendorIdentifier, ok := KWO(kwArgs, KWVendorIdentifier, -1)
+		if _debug != nil {
+			_debug("    - keyword vendor identifier: %r", vendorIdentifier)
+		}
+
+		if !ok {
+			vendorIdentifier, ok = KWO[int](iniArg, "vendorIdentifier", -1)
+			_debug("    - INI vendor identifier: %r", vendorIdentifier)
+		}
+
+		if !ok {
+			return nil, errors.New("vendorIdentifier required to auto-register the LocalDeviceObject class")
+		}
+
+		if _, err := RegisterObjectType(NKW(KWCls, l, KWVendorIdentifier, vendorIdentifier)); err != nil {
+			return nil, errors.Wrap(err, "error register object type")
+		}
+	}
+
+	// look for properties, fill in values from the keyword arguments or
+	// the INI parameter (converted to a proper value) if it was provided
+	for propid, prop := range l.DeviceObject.Get_Properties() {
+		// special processing for object identifier
+		if propid == "objectIdentifier" {
+			continue
+		}
+
+		// use keyword argument if it was provided
+		var propValue any
+		var propDataType any
+		if v, ok := kwArgs[KnownKey(propid)]; ok {
+			propValue = v
+		} else {
+			propValue, ok = KWO[any](iniArg, KnownKey(strings.ToLower(propid)), nil)
+			if !ok {
+				continue
+			}
+
+			propDataType = prop.GetDataType()
+			// TODO: convert
+			_ = propDataType
+			// at long last
+			initArgs[KnownKey(propid)] = propValue
+		}
+	}
+	// check for object identifier as a keyword parameter or in the INI file,
+	// and it might be just an int, so make it a tuple if necessary
+	var objectIdentifier any
+	if v, ok := KWO[any](kwArgs, "objectIdentifier", nil); ok {
+		objectIdentifier = v
+		if vint, ok := v.(int); ok {
+			objectIdentifier = ObjectIdentifierTuple{Left: "device", Right: vint}
+		}
+	} else if v, ok = KWO[any](iniArg, "objectidentifier", nil); ok {
+		objectIdentifier = ObjectIdentifierTuple{Left: "device", Right: v.(int)}
+	} else {
+		return nil, errors.New("objectIdentifier required")
+	}
+	initArgs["objectIdentifier"] = objectIdentifier
+	if _debug != nil {
+		_debug("    - object identifier: %r", objectIdentifier)
+	}
+
+	// fill in default property values not in init_args
+	for attr, value := range l.defaultProperties {
+		if _, ok := initArgs[KnownKey(attr)]; !ok {
+			initArgs[KnownKey(attr)] = value
+		}
+	}
+
+	// check for properties this class implements
+	if _, ok := initArgs[KnownKey("localDate")]; ok {
+		return nil, errors.New("localDate is provided by LocalDeviceObject and cannot be overridden")
+	}
+	if _, ok := initArgs[KnownKey("localTime")]; ok {
+		return nil, errors.New("localTime is provided by LocalDeviceObject and cannot be overridden")
+	}
+	if _, ok := initArgs[KnownKey("protocolServicesSupported")]; ok {
+		return nil, errors.New("protocolServicesSupported is provided by LocalDeviceObject and cannot be overridden")
+	}
+
+	// the object list is provided
+	if _, ok := initArgs[KnownKey("objectList")]; ok {
+		return nil, errors.New("objectList is provided by LocalDeviceObject and cannot be overridden")
+	}
+	initArgs["objectList"] = ArrayOfEs[ObjectIdentifier](NewObjectIdentifier, 0, nil)
+
+	// check for a minimum value
+	if v, ok := KWO[int](kwArgs, "maxApduLengthAccepted", 0); ok && v < 50 {
+		return nil, errors.New("invalid max APDU length accepted")
+	}
+
+	// dump the updated attributes
+	if _debug != nil {
+		_debug("    - init_args: %r", initArgs)
+	}
+
+	// proceed as usual
+	// TODO: how?
+
+	// pass along special property values that are not BACnet properties
+	for key, value := range kwArgs {
+		if strings.HasPrefix(string(key), "_") {
+			l.DeviceObject.SetAttr(string(key), value)
+		}
+	}
 	return l, nil
 }
 
+type _LocalDeviceObject struct {
+	*CurrentPropertyListMixIn
+	*DeviceObject
+	*DefaultRFormatter
+
+	properties        []Property
+	defaultProperties map[string]any
+
+	App any `ignore:"true"` // TODO: is *Application but creates a circular dependency. figure out what is a smart way
+}
+
+var _ Object = (*_LocalDeviceObject)(nil)
+
 func (l *_LocalDeviceObject) GetObjectIdentifier() string {
 	attr, ok := l.CurrentPropertyListMixIn.GetAttr("objectIdentifier")
 	if !ok {
@@ -172,3 +303,48 @@ func (l *_LocalDeviceObject) GetObjectList() []string {
 func (l *_LocalDeviceObject) SetObjectList(strings []string) {
 	l.CurrentPropertyListMixIn.SetAttr("objectList", strings)
 }
+
+func (l *_LocalDeviceObject) GetAttr(name string) (any, bool) {
+	// ambiguous selector avoidance
+	return l.DeviceObject.GetAttr(name)
+}
+
+func (l *_LocalDeviceObject) SetAttr(name string, value any) {
+	// ambiguous selector avoidance
+	l.DeviceObject.SetAttr(name, value)
+}
+
+func (l *_LocalDeviceObject) AddProperty(prop Property) {
+	// ambiguous selector avoidance
+	l.DeviceObject.AddProperty(prop)
+}
+
+func (l *_LocalDeviceObject) ReadProperty(args Args, kwArgs KWArgs) error {
+	// ambiguous selector avoidance
+	return l.DeviceObject.ReadProperty(args, kwArgs)
+}
+
+func (l *_LocalDeviceObject) WriteProperty(args Args, kwArgs KWArgs) error {
+	// ambiguous selector avoidance
+	return l.DeviceObject.WriteProperty(args, kwArgs)
+}
+
+func (l *_LocalDeviceObject) DeleteProperty(prop string) {
+	// ambiguous selector avoidance
+	l.DeviceObject.DeleteProperty(prop)
+}
+
+func (l *_LocalDeviceObject) Get_Properties() map[string]Property {
+	// ambiguous selector avoidance
+	return l.DeviceObject.Get_Properties()
+}
+
+func (l *_LocalDeviceObject) Set_Properties(_properties map[string]Property) {
+	// ambiguous selector avoidance
+	l.DeviceObject.Set_Properties(_properties)
+}
+
+func (l *_LocalDeviceObject) PrintDebugContents(indent int, file io.Writer, _ids []uintptr) {
+	// ambiguous selector avoidance
+	l.DeviceObject.PrintDebugContents(indent, file, _ids)
+}
diff --git a/plc4go/internal/bacnetip/bacgopes/object/object.go b/plc4go/internal/bacnetip/bacgopes/object/object.go
index 5c58a24da2..3d9df31245 100644
--- a/plc4go/internal/bacnetip/bacgopes/object/object.go
+++ b/plc4go/internal/bacnetip/bacgopes/object/object.go
@@ -32,22 +32,49 @@ import (
 
 var _debug = CreateDebugPrinter()
 
-var _arrayOfMap map[any]func(Args, KWArgs) (PropertyKlass, error)
-var _arrayOfClasses map[any]struct{}
-var _sequenceOfClasses map[any]struct{}
-var _listOfClasses map[any]struct{}
-
-func init() {
-	_arrayOfMap = make(map[any]func(Args, KWArgs) (PropertyKlass, error))
-	_arrayOfClasses = make(map[any]struct{})
-	_sequenceOfClasses = make(map[any]struct{})
-	_listOfClasses = make(map[any]struct{})
-}
+var _arrayOfMap = make(map[any]func(Args, KWArgs) (PropertyKlass, error))
+var _listOfMap = make(map[any]func(Args, KWArgs) (PropertyKlass, error))
+var _arrayOfClasses = make(map[any]struct{})
+var _sequenceOfClasses = make(map[any]struct{})
+var _listOfClasses = make(map[any]struct{})
+
+var RegisteredObjectTypes = make(map[any]struct{})
+
+func RegisterObjectType(kwargs KWArgs) (any, error) {
+	cls, aCls := KWO[any](kwargs, KWCls, nil)
+	vendorId, _ := KWO[int](kwargs, KWVendorIdentifier, 0)
+
+	if _debug != nil {
+		_debug("register_object_type %r vendor_id=%s", cls, vendorId)
+	}
+
+	if !aCls {
+		panic("implement me")
+	}
+
+	// make sure it's an Object derived class
+	if _, ok := cls.(Object); !ok {
+		return nil, errors.New("Object derived struct required")
+	}
 
-var registeredObjectTypes map[any]struct{}
+	// build a property dictionary by going through the class and all its parents
+	_properties := map[string]Property{}
+	// TODO: how?
 
-func init() {
-	registeredObjectTypes = make(map[any]struct{})
+	// if the object type hasn't been provided, make an immutable one
+	if _, ok := _properties["objectType"]; ok {
+		_properties["objectType"] = NewReadableProperty("objectType", func(args Args, _ KWArgs) (PropertyKlass, error) { return NewObjectType(args) }, WithPropertyMutable(false))
+	}
+
+	// store it in the struct
+	cls.(interface {
+		Set_Properties(_properties map[string]Property)
+	}).Set_Properties(_properties)
+
+	RegisteredObjectTypes[cls] = struct{}{} // TODO: key needs to be objectType + vendor id
+
+	// return the struct as decorator
+	return cls, nil
 }
 
 type PropertyError struct {
@@ -95,23 +122,25 @@ type _ArrayOf[T any] struct {
 	prototype   any
 }
 
-func (a _ArrayOf[T]) Encode(arg Arg) (O error) {
+var _ PropertyKlass = (*_ArrayOf[any])(nil)
+
+func (a *_ArrayOf[T]) Encode(arg Arg) (O error) {
 	panic("implement me")
 }
 
-func ArrayOfP[T any](b func(arg Arg) (*T, error), fixedLength int, prototype any) func(Args, KWArgs) (PropertyKlass, error) {
-	return ArrayOfsP(func(args Args) (*T, error) {
+func ArrayOfP[T any](klass func(arg Arg) (*T, error), fixedLength int, prototype any) func(Args, KWArgs) (PropertyKlass, error) {
+	return ArrayOfPs(func(args Args) (*T, error) {
 		if len(args) == 0 {
-			return b(NoArgs)
+			return klass(NoArgs)
 		}
 		if len(args) > 1 {
 			panic(fmt.Sprintf("oh no %d", len(args)))
 		}
-		return b(args[0])
+		return klass(args[0])
 	}, fixedLength, prototype)
 }
 
-func ArrayOfsP[T any](klass func(args Args) (*T, error), fixedLength int, prototype any) func(Args, KWArgs) (PropertyKlass, error) {
+func ArrayOfPs[T any](klass func(args Args) (*T, error), fixedLength int, prototype any) func(Args, KWArgs) (PropertyKlass, error) {
 	elementKlass, err := klass(NoArgs)
 	if err != nil {
 		return func(_ Args, _ KWArgs) (PropertyKlass, error) {
@@ -178,7 +207,78 @@ func ArrayOfsP[T any](klass func(args Args) (*T, error), fixedLength int, protot
 	}
 }
 
-// TODO: finish // convert to kwArgs and check wtf we are doing here...
+// TODO: big WIP
+type _ListOf[T any] struct {
+	name    string
+	subType func(Args) (*T, error)
+}
+
+func (a _ListOf[T]) Encode(arg Arg) (O error) {
+	panic("implement me")
+}
+
 func ListOfP[T any](b func(arg Arg) (*T, error)) func(Args, KWArgs) (PropertyKlass, error) {
-	panic("finish me")
+	return ListOfPs(func(args Args) (*T, error) {
+		if len(args) == 0 {
+			return b(NoArgs)
+		}
+		if len(args) > 1 {
+			panic(fmt.Sprintf("oh no %d", len(args)))
+		}
+		return b(args[0])
+	})
+}
+
+func ListOfPs[T any](klass func(args Args) (*T, error)) func(Args, KWArgs) (PropertyKlass, error) {
+	elementKlass, err := klass(NoArgs)
+	if err != nil {
+		return func(_ Args, _ KWArgs) (PropertyKlass, error) {
+			return nil, errors.Wrap(err, "can't get zero object")
+		}
+	}
+	switch any(elementKlass).(type) {
+	case IsAtomic:
+	// TODO: add prototype check...
+	default:
+		// TODO: add check
+	}
+
+	// if this has already been built, return the cached one
+	if v, ok := _listOfMap[fmt.Sprintf("%T", elementKlass)]; ok {
+		return v
+	}
+
+	// no ArrayOf(ArrayOf(...)) allowed
+	if _, ok := _listOfClasses[fmt.Sprintf("%T", elementKlass)]; ok {
+		return func(_ Args, _ KWArgs) (PropertyKlass, error) {
+			return nil, errors.New("nested lists disallowed")
+		}
+	}
+	// no ArrayOf(SequenceOf(...)) allowed
+	if _, ok := _arrayOfClasses[fmt.Sprintf("%T", elementKlass)]; ok {
+		return func(_ Args, _ KWArgs) (PropertyKlass, error) {
+			return nil, errors.New("list of arrays disallowed")
+		}
+	}
+
+	// define a generic class for lists
+	_listOf := struct {
+		*_ListOf[T]
+	}{&_ListOf[T]{}}
+
+	// constrain it to a list of a specific type of item
+	_listOf.subType = klass
+
+	// update the name
+	_listOf.name = "ListOf" + fmt.Sprintf("%T", elementKlass)
+
+	// cache this type
+	_listOfMap[fmt.Sprintf("%T", elementKlass)] = func(_ Args, _ KWArgs) (PropertyKlass, error) {
+		return _listOf, nil
+	}
+	_listOfClasses[fmt.Sprintf("%T", _listOf)] = struct{}{}
+
+	return func(args Args, kwArgs KWArgs) (PropertyKlass, error) {
+		return _listOf, nil
+	}
 }
diff --git a/plc4go/internal/bacnetip/bacgopes/object/object_BitStringValueObject.go b/plc4go/internal/bacnetip/bacgopes/object/object_BitStringValueObject.go
index 2135ee6022..1f41bf4b95 100644
--- a/plc4go/internal/bacnetip/bacgopes/object/object_BitStringValueObject.go
+++ b/plc4go/internal/bacnetip/bacgopes/object/object_BitStringValueObject.go
@@ -46,7 +46,7 @@ func NewBitStringValueObject(arg Arg) (*BitStringValueObject, error) {
 			NewOptionalProperty("relinquishDefault", Vs2P(NewBitString)),
 			NewOptionalProperty("timeDelay", V2P(NewUnsigned)),
 			NewOptionalProperty("notificationClass", V2P(NewUnsigned)),
-			NewOptionalProperty("alarmValues", ArrayOfsP(NewBitString, 0, 0)),
+			NewOptionalProperty("alarmValues", ArrayOfPs(NewBitString, 0, 0)),
 			NewOptionalProperty("bitMask", Vs2P(NewBitString)),
 			NewOptionalProperty("eventEnable", V2P(NewEventTransitionBits)),
 			NewOptionalProperty("ackedTransitions", V2P(NewEventTransitionBits)),
diff --git a/plc4go/internal/bacnetip/bacgopes/object/object_DeviceObject.go b/plc4go/internal/bacnetip/bacgopes/object/object_DeviceObject.go
index ae84ffea2a..bedb16d345 100644
--- a/plc4go/internal/bacnetip/bacgopes/object/object_DeviceObject.go
+++ b/plc4go/internal/bacnetip/bacgopes/object/object_DeviceObject.go
@@ -20,6 +20,8 @@
 package object
 
 import (
+	"github.com/pkg/errors"
+
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/basetypes"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 	. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/primitivedata"
@@ -47,8 +49,8 @@ func NewDeviceObject(arg Arg) (*DeviceObject, error) {
 			NewReadableProperty("protocolRevision", V2P(NewUnsigned)),
 			NewReadableProperty("protocolServicesSupported", V2P(NewServicesSupported)),
 			NewReadableProperty("protocolObjectTypesSupported", V2P(NewObjectTypesSupported)),
-			NewReadableProperty("objectList", ArrayOfsP(NewObjectIdentifier, 0, 0)),
-			NewOptionalProperty("structuredObjectList", ArrayOfsP(NewObjectIdentifier, 0, 0)),
+			NewReadableProperty("objectList", ArrayOfPs(NewObjectIdentifier, 0, 0)),
+			NewOptionalProperty("structuredObjectList", ArrayOfPs(NewObjectIdentifier, 0, 0)),
 			NewReadableProperty("maxApduLengthAccepted", V2P(NewUnsigned)),
 			NewReadableProperty("segmentationSupported", V2P(NewSegmentation)),
 			NewOptionalProperty("vtClassesSupported", ListOfP(NewVTClass)),
@@ -65,7 +67,7 @@ func NewDeviceObject(arg Arg) (*DeviceObject, error) {
 			NewOptionalProperty("maxInfoFrames", V2P(NewUnsigned)),
 			NewReadableProperty("deviceAddressBinding", ListOfP(NewAddressBinding)),
 			NewReadableProperty("databaseRevision", V2P(NewUnsigned)),
-			NewOptionalProperty("configurationFiles", ArrayOfsP(NewObjectIdentifier, 0, 0)),
+			NewOptionalProperty("configurationFiles", ArrayOfPs(NewObjectIdentifier, 0, 0)),
 			NewOptionalProperty("lastRestoreTime", V2P(NewTimeStamp)),
 			NewOptionalProperty("backupFailureTimeout", V2P(NewUnsigned)),
 			NewOptionalProperty("backupPreparationTime", V2P(NewUnsigned)),
@@ -104,6 +106,13 @@ func NewDeviceObject(arg Arg) (*DeviceObject, error) {
 			NewOptionalProperty("deployedProfileLocation", V2P(NewCharacterString)),
 		},
 	}
-	// TODO: @register_object_type
+	var err error
+	o.Object, err = NewObject(NoKWArgs())
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating object")
+	}
+	if _, err := RegisterObjectType(NKW(KWCls, o)); err != nil {
+		return nil, errors.Wrap(err, "error registering object type")
+	}
 	return o, nil
 }
diff --git a/plc4go/internal/bacnetip/bacgopes/object/object_ElevatorGroupObject.go b/plc4go/internal/bacnetip/bacgopes/object/object_ElevatorGroupObject.go
index 7a4c85b3e5..d8c1038d21 100644
--- a/plc4go/internal/bacnetip/bacgopes/object/object_ElevatorGroupObject.go
+++ b/plc4go/internal/bacnetip/bacgopes/object/object_ElevatorGroupObject.go
@@ -38,7 +38,7 @@ func NewElevatorGroupObject(arg Arg) (*ElevatorGroupObject, error) {
 		properties: []Property{
 			NewReadableProperty("machineRoomID", Vs2P(NewObjectIdentifier)),
 			NewReadableProperty("groupID", V2P(NewUnsigned8)),
-			NewReadableProperty("groupMembers", ArrayOfsP(NewObjectIdentifier, 0, 0)),
+			NewReadableProperty("groupMembers", ArrayOfPs(NewObjectIdentifier, 0, 0)),
 			NewOptionalProperty("groupMode", V2P(NewLiftGroupMode)),
 			NewOptionalProperty("landingCalls", ListOfP(NewLandingCallStatus)),
 			NewOptionalProperty("landingCallControl", V2P(NewLandingCallStatus)),
diff --git a/plc4go/internal/bacnetip/bacgopes/object/object_Object.go b/plc4go/internal/bacnetip/bacgopes/object/object_Object.go
index 93d8d0f325..cffcbf1ea0 100644
--- a/plc4go/internal/bacnetip/bacgopes/object/object_Object.go
+++ b/plc4go/internal/bacnetip/bacgopes/object/object_Object.go
@@ -39,6 +39,8 @@ type Object interface {
 	DeleteProperty(prop string)
 	ReadProperty(Args, KWArgs) error
 	WriteProperty(Args, KWArgs) error
+	Set_Properties(_properties map[string]Property)
+	Get_Properties() map[string]Property
 }
 
 type _Object struct {
@@ -64,7 +66,7 @@ func NewObject(kwArgs KWArgs, options ...Option) (Object, error) {
 			NewReadableProperty("propertyList", ArrayOfP(NewPropertyIdentifier, 0, 0)),
 			NewOptionalProperty("auditLevel", V2P(NewAuditLevel)),
 			NewOptionalProperty("auditableOperations", V2P(NewAuditOperationFlags)),
-			NewOptionalProperty("tags", ArrayOfsP(NewNameValue, 0, 0)),
+			NewOptionalProperty("tags", ArrayOfPs(NewNameValue, 0, 0)),
 			NewOptionalProperty("profileLocation", V2P(NewCharacterString)),
 			NewOptionalProperty("profileName", V2P(NewCharacterString)),
 		},
@@ -136,6 +138,14 @@ func WithObject_Properties(_properties map[string]Property) GenericApplier[*_Obj
 	})
 }
 
+func (o *_Object) Set_Properties(_properties map[string]Property) {
+	o._properties = _properties
+}
+
+func (o *_Object) Get_Properties() map[string]Property {
+	return o._properties
+}
+
 func (o *_Object) PrintDebugContents(indent int, file io.Writer, _ids []uintptr) {
 	//TODO implement me
 	panic("implement me")
diff --git a/plc4go/internal/bacnetip/bacgopes/object/object_Property.go b/plc4go/internal/bacnetip/bacgopes/object/object_Property.go
index 5abdb3c705..c75c01b122 100644
--- a/plc4go/internal/bacnetip/bacgopes/object/object_Property.go
+++ b/plc4go/internal/bacnetip/bacgopes/object/object_Property.go
@@ -25,6 +25,7 @@ import . "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
 type Property interface {
 	ReadProperty(args Args, kwArgs KWArgs) error
 	WriteProperty(args Args, kwArgs KWArgs) error
+	GetDataType() any
 	IsOptional() bool
 	Get_Default() any
 	IsMutable() bool
@@ -34,21 +35,30 @@ type PropertyKlass interface {
 	Encode(Arg) error
 }
 
-func NewProperty(name string, klass func(Args, KWArgs) (PropertyKlass, error), options ...Option) Property {
+func NewProperty(identifier string, datatype func(Args, KWArgs) (PropertyKlass, error), options ...Option) Property {
 	i := &_Property{
-		name:  name,
-		klass: klass,
+		// keep the arguments
+		identifier: identifier,
+		dataType:   datatype,
 	}
 	ApplyAppliers(options, i)
+
+	// check the datatype
+	dataType, _ := i.dataType(Nothing())
+	switch dataType.(type) {
+	default:
+		// TODO: check for Atomic, Sequence, Choice, Array, List, AnyAtomic
+	}
+
 	return i
 }
 
 type _Property struct {
-	name     string
-	klass    func(Args, KWArgs) (PropertyKlass, error)
-	optional bool
-	_default any
-	mutable  bool
+	identifier string
+	dataType   func(Args, KWArgs) (PropertyKlass, error)
+	optional   bool
+	_default   any
+	mutable    bool
 }
 
 var _ Property = (*_Property)(nil)
@@ -65,6 +75,10 @@ func WithPropertyMutable(mutable bool) GenericApplier[*_Property] {
 	return WrapGenericApplier(func(e *_Property) { e.mutable = mutable })
 }
 
+func (p *_Property) GetDataType() any {
+	return p.dataType
+}
+
 func (p *_Property) IsOptional() bool {
 	return p.optional
 }