You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2022/05/18 11:48:20 UTC

[plc4x] branch develop updated: feat(bacnet): implemented support for LIFE_SAFETY_ALARM_VALUES

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 7a75b2c574 feat(bacnet): implemented support for LIFE_SAFETY_ALARM_VALUES
7a75b2c574 is described below

commit 7a75b2c57491640e0b74aad5cbd5983f051b0036
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed May 18 13:48:12 2022 +0200

    feat(bacnet): implemented support for LIFE_SAFETY_ALARM_VALUES
---
 .../plc4go/bacnetip/readwrite/ParserHelper.go      |   2 +
 .../plc4go/bacnetip/readwrite/XmlParserHelper.go   |   2 +
 .../readwrite/model/BACnetConstructedData.go       |   6 +-
 .../BACnetConstructedDataLifeSafetyAlarmValues.go  | 223 ++++++++++++++++
 ...netConstructedDataLifeSafetyAlarmValuesEntry.go | 241 +++++++++++++++++
 .../readwrite/model/BACnetLifeSafetyState.go       | 297 +++++++++++++++++++++
 .../bacnetip/readwrite/model/StaticHelper.go       |   7 +
 .../bacnetip/readwrite/utils/StaticHelper.java     |   5 +
 .../plc4x/java/bacnetip/ManualBacNetDecoder.java   |  38 ++-
 .../plc4x/java/bacnetip/RandomPackagesTest.java    |   8 +-
 .../plc4x/java/bacnetip/TrickyPackagesTest.java    |  21 +-
 .../java/org/apache/plc4x/java/bacnetip/Utils.java |  32 +++
 .../bacnet/src/test/resources/logback-test.xml     |   5 +-
 .../resources/protocols/bacnetip/bacnetip.mspec    |  68 +++--
 14 files changed, 900 insertions(+), 55 deletions(-)

diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/ParserHelper.go b/plc4go/internal/plc4go/bacnetip/readwrite/ParserHelper.go
index 48beace135..9a5b73accf 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/ParserHelper.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/ParserHelper.go
@@ -243,6 +243,8 @@ func (m BacnetipParserHelper) Parse(typeName string, arguments []string, io util
 			return nil, errors.Wrap(err, "Error parsing")
 		}
 		return model.BACnetTimeStampsEnclosedParse(io, tagNumber)
+	case "BACnetConstructedDataLifeSafetyAlarmValuesEntry":
+		return model.BACnetConstructedDataLifeSafetyAlarmValuesEntryParse(io)
 	case "BACnetConfirmedServiceRequest":
 		serviceRequestLength, err := utils.StrToUint16(arguments[0])
 		if err != nil {
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/XmlParserHelper.go b/plc4go/internal/plc4go/bacnetip/readwrite/XmlParserHelper.go
index 627ab4c782..3b328ec6d7 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/XmlParserHelper.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/XmlParserHelper.go
@@ -280,6 +280,8 @@ func (m BacnetipXmlParserHelper) Parse(typeName string, xmlString string, parser
 		}
 		tagNumber := uint8(parsedUint0)
 		return model.BACnetTimeStampsEnclosedParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)), tagNumber)
+	case "BACnetConstructedDataLifeSafetyAlarmValuesEntry":
+		return model.BACnetConstructedDataLifeSafetyAlarmValuesEntryParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
 	case "BACnetConfirmedServiceRequest":
 		parsedUint0, err := strconv.ParseUint(parserArguments[0], 10, 16)
 		if err != nil {
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConstructedData.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConstructedData.go
index 37dc047846..4d48543a0d 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConstructedData.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConstructedData.go
@@ -183,16 +183,14 @@ func BACnetConstructedDataParse(readBuffer utils.ReadBuffer, tagNumber uint8, ob
 	var _child BACnetConstructedDataChild
 	var typeSwitchError error
 	switch {
-	case objectType == BACnetObjectType_LIFE_SAFETY_ZONE && propertyIdentifierEnum == BACnetPropertyIdentifier_ZONE_MEMBERS: // BACnetConstructedDataLifeSafetyZoneMembers
-		_child, typeSwitchError = BACnetConstructedDataLifeSafetyZoneMembersParse(readBuffer, tagNumber, objectType, propertyIdentifierArgument)
-	case objectType == BACnetObjectType_LIFE_SAFETY_ZONE && propertyIdentifierEnum == BACnetPropertyIdentifier_MEMBER_OF: // BACnetConstructedDataLifeSafetyZoneMemberOf
-		_child, typeSwitchError = BACnetConstructedDataLifeSafetyZoneMemberOfParse(readBuffer, tagNumber, objectType, propertyIdentifierArgument)
 	case objectType == BACnetObjectType_LOOP && propertyIdentifierEnum == BACnetPropertyIdentifier_ACTION: // BACnetConstructedDataLoopAction
 		_child, typeSwitchError = BACnetConstructedDataLoopActionParse(readBuffer, tagNumber, objectType, propertyIdentifierArgument)
 	case true && propertyIdentifierEnum == BACnetPropertyIdentifier_ACTION: // BACnetConstructedDataAction
 		_child, typeSwitchError = BACnetConstructedDataActionParse(readBuffer, tagNumber, objectType, propertyIdentifierArgument)
 	case true && propertyIdentifierEnum == BACnetPropertyIdentifier_EVENT_TIME_STAMPS: // BACnetConstructedDataEventTimestamps
 		_child, typeSwitchError = BACnetConstructedDataEventTimestampsParse(readBuffer, tagNumber, objectType, propertyIdentifierArgument)
+	case true && propertyIdentifierEnum == BACnetPropertyIdentifier_LIFE_SAFETY_ALARM_VALUES: // BACnetConstructedDataLifeSafetyAlarmValues
+		_child, typeSwitchError = BACnetConstructedDataLifeSafetyAlarmValuesParse(readBuffer, tagNumber, objectType, propertyIdentifierArgument)
 	case true && propertyIdentifierEnum == BACnetPropertyIdentifier_LIST_OF_OBJECT_PROPERTY_REFERENCES: // BACnetConstructedDataListOfObjectPropertyReferences
 		_child, typeSwitchError = BACnetConstructedDataListOfObjectPropertyReferencesParse(readBuffer, tagNumber, objectType, propertyIdentifierArgument)
 	case true && propertyIdentifierEnum == BACnetPropertyIdentifier_MEMBER_OF: // BACnetConstructedDataMemberOf
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConstructedDataLifeSafetyAlarmValues.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConstructedDataLifeSafetyAlarmValues.go
new file mode 100644
index 0000000000..a49375c861
--- /dev/null
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConstructedDataLifeSafetyAlarmValues.go
@@ -0,0 +1,223 @@
+/*
+ * 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.
+
+// BACnetConstructedDataLifeSafetyAlarmValues is the data-structure of this message
+type BACnetConstructedDataLifeSafetyAlarmValues struct {
+	*BACnetConstructedData
+	AlarmValues []*BACnetConstructedDataLifeSafetyAlarmValuesEntry
+
+	// Arguments.
+	TagNumber                  uint8
+	PropertyIdentifierArgument BACnetContextTagPropertyIdentifier
+}
+
+// IBACnetConstructedDataLifeSafetyAlarmValues is the corresponding interface of BACnetConstructedDataLifeSafetyAlarmValues
+type IBACnetConstructedDataLifeSafetyAlarmValues interface {
+	IBACnetConstructedData
+	// GetAlarmValues returns AlarmValues (property field)
+	GetAlarmValues() []*BACnetConstructedDataLifeSafetyAlarmValuesEntry
+	// GetLengthInBytes returns the length in bytes
+	GetLengthInBytes() uint16
+	// GetLengthInBits returns the length in bits
+	GetLengthInBits() uint16
+	// Serialize serializes this type
+	Serialize(writeBuffer utils.WriteBuffer) error
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for discriminator values.
+///////////////////////
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValues) GetObjectType() BACnetObjectType {
+	return 0
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValues) InitializeParent(parent *BACnetConstructedData, openingTag *BACnetOpeningTag, closingTag *BACnetClosingTag) {
+	m.BACnetConstructedData.OpeningTag = openingTag
+	m.BACnetConstructedData.ClosingTag = closingTag
+}
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValues) GetParent() *BACnetConstructedData {
+	return m.BACnetConstructedData
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for property fields.
+///////////////////////
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValues) GetAlarmValues() []*BACnetConstructedDataLifeSafetyAlarmValuesEntry {
+	return m.AlarmValues
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+// NewBACnetConstructedDataLifeSafetyAlarmValues factory function for BACnetConstructedDataLifeSafetyAlarmValues
+func NewBACnetConstructedDataLifeSafetyAlarmValues(alarmValues []*BACnetConstructedDataLifeSafetyAlarmValuesEntry, openingTag *BACnetOpeningTag, closingTag *BACnetClosingTag, tagNumber uint8, propertyIdentifierArgument BACnetContextTagPropertyIdentifier) *BACnetConstructedDataLifeSafetyAlarmValues {
+	_result := &BACnetConstructedDataLifeSafetyAlarmValues{
+		AlarmValues:           alarmValues,
+		BACnetConstructedData: NewBACnetConstructedData(openingTag, closingTag, tagNumber, propertyIdentifierArgument),
+	}
+	_result.Child = _result
+	return _result
+}
+
+func CastBACnetConstructedDataLifeSafetyAlarmValues(structType interface{}) *BACnetConstructedDataLifeSafetyAlarmValues {
+	if casted, ok := structType.(BACnetConstructedDataLifeSafetyAlarmValues); ok {
+		return &casted
+	}
+	if casted, ok := structType.(*BACnetConstructedDataLifeSafetyAlarmValues); ok {
+		return casted
+	}
+	if casted, ok := structType.(BACnetConstructedData); ok {
+		return CastBACnetConstructedDataLifeSafetyAlarmValues(casted.Child)
+	}
+	if casted, ok := structType.(*BACnetConstructedData); ok {
+		return CastBACnetConstructedDataLifeSafetyAlarmValues(casted.Child)
+	}
+	return nil
+}
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValues) GetTypeName() string {
+	return "BACnetConstructedDataLifeSafetyAlarmValues"
+}
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValues) GetLengthInBits() uint16 {
+	return m.GetLengthInBitsConditional(false)
+}
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValues) GetLengthInBitsConditional(lastItem bool) uint16 {
+	lengthInBits := uint16(m.GetParentLengthInBits())
+
+	// Array field
+	if len(m.AlarmValues) > 0 {
+		for _, element := range m.AlarmValues {
+			lengthInBits += element.GetLengthInBits()
+		}
+	}
+
+	return lengthInBits
+}
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValues) GetLengthInBytes() uint16 {
+	return m.GetLengthInBits() / 8
+}
+
+func BACnetConstructedDataLifeSafetyAlarmValuesParse(readBuffer utils.ReadBuffer, tagNumber uint8, objectType BACnetObjectType, propertyIdentifierArgument *BACnetContextTagPropertyIdentifier) (*BACnetConstructedDataLifeSafetyAlarmValues, error) {
+	positionAware := readBuffer
+	_ = positionAware
+	if pullErr := readBuffer.PullContext("BACnetConstructedDataLifeSafetyAlarmValues"); pullErr != nil {
+		return nil, pullErr
+	}
+	currentPos := positionAware.GetPos()
+	_ = currentPos
+
+	// Array field (alarmValues)
+	if pullErr := readBuffer.PullContext("alarmValues", utils.WithRenderAsList(true)); pullErr != nil {
+		return nil, pullErr
+	}
+	// Terminated array
+	alarmValues := make([]*BACnetConstructedDataLifeSafetyAlarmValuesEntry, 0)
+	{
+		for !bool(IsBACnetConstructedDataClosingTag(readBuffer, false, tagNumber)) {
+			_item, _err := BACnetConstructedDataLifeSafetyAlarmValuesEntryParse(readBuffer)
+			if _err != nil {
+				return nil, errors.Wrap(_err, "Error parsing 'alarmValues' field")
+			}
+			alarmValues = append(alarmValues, CastBACnetConstructedDataLifeSafetyAlarmValuesEntry(_item))
+
+		}
+	}
+	if closeErr := readBuffer.CloseContext("alarmValues", utils.WithRenderAsList(true)); closeErr != nil {
+		return nil, closeErr
+	}
+
+	if closeErr := readBuffer.CloseContext("BACnetConstructedDataLifeSafetyAlarmValues"); closeErr != nil {
+		return nil, closeErr
+	}
+
+	// Create a partially initialized instance
+	_child := &BACnetConstructedDataLifeSafetyAlarmValues{
+		AlarmValues:           alarmValues,
+		BACnetConstructedData: &BACnetConstructedData{},
+	}
+	_child.BACnetConstructedData.Child = _child
+	return _child, nil
+}
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValues) Serialize(writeBuffer utils.WriteBuffer) error {
+	positionAware := writeBuffer
+	_ = positionAware
+	ser := func() error {
+		if pushErr := writeBuffer.PushContext("BACnetConstructedDataLifeSafetyAlarmValues"); pushErr != nil {
+			return pushErr
+		}
+
+		// Array Field (alarmValues)
+		if m.AlarmValues != nil {
+			if pushErr := writeBuffer.PushContext("alarmValues", utils.WithRenderAsList(true)); pushErr != nil {
+				return pushErr
+			}
+			for _, _element := range m.AlarmValues {
+				_elementErr := _element.Serialize(writeBuffer)
+				if _elementErr != nil {
+					return errors.Wrap(_elementErr, "Error serializing 'alarmValues' field")
+				}
+			}
+			if popErr := writeBuffer.PopContext("alarmValues", utils.WithRenderAsList(true)); popErr != nil {
+				return popErr
+			}
+		}
+
+		if popErr := writeBuffer.PopContext("BACnetConstructedDataLifeSafetyAlarmValues"); popErr != nil {
+			return popErr
+		}
+		return nil
+	}
+	return m.SerializeParent(writeBuffer, m, ser)
+}
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValues) String() string {
+	if m == nil {
+		return "<nil>"
+	}
+	buffer := utils.NewBoxedWriteBufferWithOptions(true, true)
+	if err := m.Serialize(buffer); err != nil {
+		return err.Error()
+	}
+	return buffer.GetBox().String()
+}
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConstructedDataLifeSafetyAlarmValuesEntry.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConstructedDataLifeSafetyAlarmValuesEntry.go
new file mode 100644
index 0000000000..7d60b74980
--- /dev/null
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConstructedDataLifeSafetyAlarmValuesEntry.go
@@ -0,0 +1,241 @@
+/*
+ * 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"
+	"io"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// BACnetConstructedDataLifeSafetyAlarmValuesEntry is the data-structure of this message
+type BACnetConstructedDataLifeSafetyAlarmValuesEntry struct {
+	RawData *BACnetApplicationTagEnumerated
+}
+
+// IBACnetConstructedDataLifeSafetyAlarmValuesEntry is the corresponding interface of BACnetConstructedDataLifeSafetyAlarmValuesEntry
+type IBACnetConstructedDataLifeSafetyAlarmValuesEntry interface {
+	// GetRawData returns RawData (property field)
+	GetRawData() *BACnetApplicationTagEnumerated
+	// GetIsLifeSafetyStateProprietary returns IsLifeSafetyStateProprietary (virtual field)
+	GetIsLifeSafetyStateProprietary() bool
+	// GetLifeSafetyState returns LifeSafetyState (virtual field)
+	GetLifeSafetyState() BACnetLifeSafetyState
+	// GetLifeSafetyStateProprietary returns LifeSafetyStateProprietary (virtual field)
+	GetLifeSafetyStateProprietary() uint16
+	// GetLengthInBytes returns the length in bytes
+	GetLengthInBytes() uint16
+	// GetLengthInBits returns the length in bits
+	GetLengthInBits() uint16
+	// Serialize serializes this type
+	Serialize(writeBuffer utils.WriteBuffer) error
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for property fields.
+///////////////////////
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValuesEntry) GetRawData() *BACnetApplicationTagEnumerated {
+	return m.RawData
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for virtual fields.
+///////////////////////
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValuesEntry) GetIsLifeSafetyStateProprietary() bool {
+	rawData := m.RawData
+	_ = rawData
+	return bool(bool(((*m.GetRawData()).GetActualValue()) > (255)))
+}
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValuesEntry) GetLifeSafetyState() BACnetLifeSafetyState {
+	rawData := m.RawData
+	_ = rawData
+	return BACnetLifeSafetyState(MapBACnetLifeSafetyState((*m.GetRawData()), m.GetIsLifeSafetyStateProprietary()))
+}
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValuesEntry) GetLifeSafetyStateProprietary() uint16 {
+	rawData := m.RawData
+	_ = rawData
+	return uint16(utils.InlineIf(m.GetIsLifeSafetyStateProprietary(), func() interface{} { return uint16((*m.GetRawData()).GetActualValue()) }, func() interface{} { return uint16(uint16(0)) }).(uint16))
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+// NewBACnetConstructedDataLifeSafetyAlarmValuesEntry factory function for BACnetConstructedDataLifeSafetyAlarmValuesEntry
+func NewBACnetConstructedDataLifeSafetyAlarmValuesEntry(rawData *BACnetApplicationTagEnumerated) *BACnetConstructedDataLifeSafetyAlarmValuesEntry {
+	return &BACnetConstructedDataLifeSafetyAlarmValuesEntry{RawData: rawData}
+}
+
+func CastBACnetConstructedDataLifeSafetyAlarmValuesEntry(structType interface{}) *BACnetConstructedDataLifeSafetyAlarmValuesEntry {
+	if casted, ok := structType.(BACnetConstructedDataLifeSafetyAlarmValuesEntry); ok {
+		return &casted
+	}
+	if casted, ok := structType.(*BACnetConstructedDataLifeSafetyAlarmValuesEntry); ok {
+		return casted
+	}
+	return nil
+}
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValuesEntry) GetTypeName() string {
+	return "BACnetConstructedDataLifeSafetyAlarmValuesEntry"
+}
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValuesEntry) GetLengthInBits() uint16 {
+	return m.GetLengthInBitsConditional(false)
+}
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValuesEntry) GetLengthInBitsConditional(lastItem bool) uint16 {
+	lengthInBits := uint16(0)
+
+	// Optional Field (rawData)
+	if m.RawData != nil {
+		lengthInBits += (*m.RawData).GetLengthInBits()
+	}
+
+	// A virtual field doesn't have any in- or output.
+
+	// A virtual field doesn't have any in- or output.
+
+	// A virtual field doesn't have any in- or output.
+
+	return lengthInBits
+}
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValuesEntry) GetLengthInBytes() uint16 {
+	return m.GetLengthInBits() / 8
+}
+
+func BACnetConstructedDataLifeSafetyAlarmValuesEntryParse(readBuffer utils.ReadBuffer) (*BACnetConstructedDataLifeSafetyAlarmValuesEntry, error) {
+	positionAware := readBuffer
+	_ = positionAware
+	if pullErr := readBuffer.PullContext("BACnetConstructedDataLifeSafetyAlarmValuesEntry"); pullErr != nil {
+		return nil, pullErr
+	}
+	currentPos := positionAware.GetPos()
+	_ = currentPos
+
+	// Optional Field (rawData) (Can be skipped, if a given expression evaluates to false)
+	var rawData *BACnetApplicationTagEnumerated = nil
+	{
+		currentPos = positionAware.GetPos()
+		if pullErr := readBuffer.PullContext("rawData"); pullErr != nil {
+			return nil, pullErr
+		}
+		_val, _err := BACnetApplicationTagParse(readBuffer)
+		switch {
+		case errors.Is(_err, utils.ParseAssertError{}) || errors.Is(_err, io.EOF):
+			readBuffer.Reset(currentPos)
+		case _err != nil:
+			return nil, errors.Wrap(_err, "Error parsing 'rawData' field")
+		default:
+			rawData = CastBACnetApplicationTagEnumerated(_val)
+			if closeErr := readBuffer.CloseContext("rawData"); closeErr != nil {
+				return nil, closeErr
+			}
+		}
+	}
+
+	// Virtual field
+	_isLifeSafetyStateProprietary := bool(((*rawData).GetActualValue()) > (255))
+	isLifeSafetyStateProprietary := bool(_isLifeSafetyStateProprietary)
+	_ = isLifeSafetyStateProprietary
+
+	// Virtual field
+	_lifeSafetyState := MapBACnetLifeSafetyState((*rawData), isLifeSafetyStateProprietary)
+	lifeSafetyState := BACnetLifeSafetyState(_lifeSafetyState)
+	_ = lifeSafetyState
+
+	// Virtual field
+	_lifeSafetyStateProprietary := utils.InlineIf(isLifeSafetyStateProprietary, func() interface{} { return uint16((*rawData).GetActualValue()) }, func() interface{} { return uint16(uint16(0)) }).(uint16)
+	lifeSafetyStateProprietary := uint16(_lifeSafetyStateProprietary)
+	_ = lifeSafetyStateProprietary
+
+	if closeErr := readBuffer.CloseContext("BACnetConstructedDataLifeSafetyAlarmValuesEntry"); closeErr != nil {
+		return nil, closeErr
+	}
+
+	// Create the instance
+	return NewBACnetConstructedDataLifeSafetyAlarmValuesEntry(rawData), nil
+}
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValuesEntry) Serialize(writeBuffer utils.WriteBuffer) error {
+	positionAware := writeBuffer
+	_ = positionAware
+	if pushErr := writeBuffer.PushContext("BACnetConstructedDataLifeSafetyAlarmValuesEntry"); pushErr != nil {
+		return pushErr
+	}
+
+	// Optional Field (rawData) (Can be skipped, if the value is null)
+	var rawData *BACnetApplicationTagEnumerated = nil
+	if m.RawData != nil {
+		if pushErr := writeBuffer.PushContext("rawData"); pushErr != nil {
+			return pushErr
+		}
+		rawData = m.RawData
+		_rawDataErr := rawData.Serialize(writeBuffer)
+		if popErr := writeBuffer.PopContext("rawData"); popErr != nil {
+			return popErr
+		}
+		if _rawDataErr != nil {
+			return errors.Wrap(_rawDataErr, "Error serializing 'rawData' field")
+		}
+	}
+	// Virtual field
+	if _isLifeSafetyStateProprietaryErr := writeBuffer.WriteVirtual("isLifeSafetyStateProprietary", m.GetIsLifeSafetyStateProprietary()); _isLifeSafetyStateProprietaryErr != nil {
+		return errors.Wrap(_isLifeSafetyStateProprietaryErr, "Error serializing 'isLifeSafetyStateProprietary' field")
+	}
+	// Virtual field
+	if _lifeSafetyStateErr := writeBuffer.WriteVirtual("lifeSafetyState", m.GetLifeSafetyState()); _lifeSafetyStateErr != nil {
+		return errors.Wrap(_lifeSafetyStateErr, "Error serializing 'lifeSafetyState' field")
+	}
+	// Virtual field
+	if _lifeSafetyStateProprietaryErr := writeBuffer.WriteVirtual("lifeSafetyStateProprietary", m.GetLifeSafetyStateProprietary()); _lifeSafetyStateProprietaryErr != nil {
+		return errors.Wrap(_lifeSafetyStateProprietaryErr, "Error serializing 'lifeSafetyStateProprietary' field")
+	}
+
+	if popErr := writeBuffer.PopContext("BACnetConstructedDataLifeSafetyAlarmValuesEntry"); popErr != nil {
+		return popErr
+	}
+	return nil
+}
+
+func (m *BACnetConstructedDataLifeSafetyAlarmValuesEntry) String() string {
+	if m == nil {
+		return "<nil>"
+	}
+	buffer := utils.NewBoxedWriteBufferWithOptions(true, true)
+	if err := m.Serialize(buffer); err != nil {
+		return err.Error()
+	}
+	return buffer.GetBox().String()
+}
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetLifeSafetyState.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetLifeSafetyState.go
new file mode 100644
index 0000000000..a19f890aed
--- /dev/null
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetLifeSafetyState.go
@@ -0,0 +1,297 @@
+/*
+ * 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 BACnetLifeSafetyState uint16
+
+type IBACnetLifeSafetyState interface {
+	Serialize(writeBuffer utils.WriteBuffer) error
+}
+
+const (
+	BACnetLifeSafetyState_QUIET            BACnetLifeSafetyState = 0
+	BACnetLifeSafetyState_PRE_ALARM        BACnetLifeSafetyState = 1
+	BACnetLifeSafetyState_ALARM            BACnetLifeSafetyState = 2
+	BACnetLifeSafetyState_FAULT            BACnetLifeSafetyState = 3
+	BACnetLifeSafetyState_FAULT_PRE_ALARM  BACnetLifeSafetyState = 4
+	BACnetLifeSafetyState_FAULT_ALARM      BACnetLifeSafetyState = 5
+	BACnetLifeSafetyState_NOT_READY        BACnetLifeSafetyState = 6
+	BACnetLifeSafetyState_ACTIVE           BACnetLifeSafetyState = 7
+	BACnetLifeSafetyState_TAMPER           BACnetLifeSafetyState = 8
+	BACnetLifeSafetyState_TEST_ALARM       BACnetLifeSafetyState = 9
+	BACnetLifeSafetyState_TEST_ACTIVE      BACnetLifeSafetyState = 10
+	BACnetLifeSafetyState_TEST_FAULT       BACnetLifeSafetyState = 11
+	BACnetLifeSafetyState_TEST_FAULT_ALARM BACnetLifeSafetyState = 12
+	BACnetLifeSafetyState_HOLDUP           BACnetLifeSafetyState = 13
+	BACnetLifeSafetyState_DURESS           BACnetLifeSafetyState = 14
+	BACnetLifeSafetyState_TAMPER_ALARM     BACnetLifeSafetyState = 15
+	BACnetLifeSafetyState_ABNORMAL         BACnetLifeSafetyState = 16
+	BACnetLifeSafetyState_EMERGENCY_POWER  BACnetLifeSafetyState = 17
+	BACnetLifeSafetyState_DELAYED          BACnetLifeSafetyState = 18
+	BACnetLifeSafetyState_BLOCKED          BACnetLifeSafetyState = 19
+	BACnetLifeSafetyState_LOCAL_ALARM      BACnetLifeSafetyState = 20
+	BACnetLifeSafetyState_GENERAL_ALARM    BACnetLifeSafetyState = 21
+	BACnetLifeSafetyState_SUPERVISORY      BACnetLifeSafetyState = 22
+	BACnetLifeSafetyState_TEST_SUPERVISORY BACnetLifeSafetyState = 23
+)
+
+var BACnetLifeSafetyStateValues []BACnetLifeSafetyState
+
+func init() {
+	_ = errors.New
+	BACnetLifeSafetyStateValues = []BACnetLifeSafetyState{
+		BACnetLifeSafetyState_QUIET,
+		BACnetLifeSafetyState_PRE_ALARM,
+		BACnetLifeSafetyState_ALARM,
+		BACnetLifeSafetyState_FAULT,
+		BACnetLifeSafetyState_FAULT_PRE_ALARM,
+		BACnetLifeSafetyState_FAULT_ALARM,
+		BACnetLifeSafetyState_NOT_READY,
+		BACnetLifeSafetyState_ACTIVE,
+		BACnetLifeSafetyState_TAMPER,
+		BACnetLifeSafetyState_TEST_ALARM,
+		BACnetLifeSafetyState_TEST_ACTIVE,
+		BACnetLifeSafetyState_TEST_FAULT,
+		BACnetLifeSafetyState_TEST_FAULT_ALARM,
+		BACnetLifeSafetyState_HOLDUP,
+		BACnetLifeSafetyState_DURESS,
+		BACnetLifeSafetyState_TAMPER_ALARM,
+		BACnetLifeSafetyState_ABNORMAL,
+		BACnetLifeSafetyState_EMERGENCY_POWER,
+		BACnetLifeSafetyState_DELAYED,
+		BACnetLifeSafetyState_BLOCKED,
+		BACnetLifeSafetyState_LOCAL_ALARM,
+		BACnetLifeSafetyState_GENERAL_ALARM,
+		BACnetLifeSafetyState_SUPERVISORY,
+		BACnetLifeSafetyState_TEST_SUPERVISORY,
+	}
+}
+
+func BACnetLifeSafetyStateByValue(value uint16) BACnetLifeSafetyState {
+	switch value {
+	case 0:
+		return BACnetLifeSafetyState_QUIET
+	case 1:
+		return BACnetLifeSafetyState_PRE_ALARM
+	case 10:
+		return BACnetLifeSafetyState_TEST_ACTIVE
+	case 11:
+		return BACnetLifeSafetyState_TEST_FAULT
+	case 12:
+		return BACnetLifeSafetyState_TEST_FAULT_ALARM
+	case 13:
+		return BACnetLifeSafetyState_HOLDUP
+	case 14:
+		return BACnetLifeSafetyState_DURESS
+	case 15:
+		return BACnetLifeSafetyState_TAMPER_ALARM
+	case 16:
+		return BACnetLifeSafetyState_ABNORMAL
+	case 17:
+		return BACnetLifeSafetyState_EMERGENCY_POWER
+	case 18:
+		return BACnetLifeSafetyState_DELAYED
+	case 19:
+		return BACnetLifeSafetyState_BLOCKED
+	case 2:
+		return BACnetLifeSafetyState_ALARM
+	case 20:
+		return BACnetLifeSafetyState_LOCAL_ALARM
+	case 21:
+		return BACnetLifeSafetyState_GENERAL_ALARM
+	case 22:
+		return BACnetLifeSafetyState_SUPERVISORY
+	case 23:
+		return BACnetLifeSafetyState_TEST_SUPERVISORY
+	case 3:
+		return BACnetLifeSafetyState_FAULT
+	case 4:
+		return BACnetLifeSafetyState_FAULT_PRE_ALARM
+	case 5:
+		return BACnetLifeSafetyState_FAULT_ALARM
+	case 6:
+		return BACnetLifeSafetyState_NOT_READY
+	case 7:
+		return BACnetLifeSafetyState_ACTIVE
+	case 8:
+		return BACnetLifeSafetyState_TAMPER
+	case 9:
+		return BACnetLifeSafetyState_TEST_ALARM
+	}
+	return 0
+}
+
+func BACnetLifeSafetyStateByName(value string) BACnetLifeSafetyState {
+	switch value {
+	case "QUIET":
+		return BACnetLifeSafetyState_QUIET
+	case "PRE_ALARM":
+		return BACnetLifeSafetyState_PRE_ALARM
+	case "TEST_ACTIVE":
+		return BACnetLifeSafetyState_TEST_ACTIVE
+	case "TEST_FAULT":
+		return BACnetLifeSafetyState_TEST_FAULT
+	case "TEST_FAULT_ALARM":
+		return BACnetLifeSafetyState_TEST_FAULT_ALARM
+	case "HOLDUP":
+		return BACnetLifeSafetyState_HOLDUP
+	case "DURESS":
+		return BACnetLifeSafetyState_DURESS
+	case "TAMPER_ALARM":
+		return BACnetLifeSafetyState_TAMPER_ALARM
+	case "ABNORMAL":
+		return BACnetLifeSafetyState_ABNORMAL
+	case "EMERGENCY_POWER":
+		return BACnetLifeSafetyState_EMERGENCY_POWER
+	case "DELAYED":
+		return BACnetLifeSafetyState_DELAYED
+	case "BLOCKED":
+		return BACnetLifeSafetyState_BLOCKED
+	case "ALARM":
+		return BACnetLifeSafetyState_ALARM
+	case "LOCAL_ALARM":
+		return BACnetLifeSafetyState_LOCAL_ALARM
+	case "GENERAL_ALARM":
+		return BACnetLifeSafetyState_GENERAL_ALARM
+	case "SUPERVISORY":
+		return BACnetLifeSafetyState_SUPERVISORY
+	case "TEST_SUPERVISORY":
+		return BACnetLifeSafetyState_TEST_SUPERVISORY
+	case "FAULT":
+		return BACnetLifeSafetyState_FAULT
+	case "FAULT_PRE_ALARM":
+		return BACnetLifeSafetyState_FAULT_PRE_ALARM
+	case "FAULT_ALARM":
+		return BACnetLifeSafetyState_FAULT_ALARM
+	case "NOT_READY":
+		return BACnetLifeSafetyState_NOT_READY
+	case "ACTIVE":
+		return BACnetLifeSafetyState_ACTIVE
+	case "TAMPER":
+		return BACnetLifeSafetyState_TAMPER
+	case "TEST_ALARM":
+		return BACnetLifeSafetyState_TEST_ALARM
+	}
+	return 0
+}
+
+func BACnetLifeSafetyStateKnows(value uint16) bool {
+	for _, typeValue := range BACnetLifeSafetyStateValues {
+		if uint16(typeValue) == value {
+			return true
+		}
+	}
+	return false
+}
+
+func CastBACnetLifeSafetyState(structType interface{}) BACnetLifeSafetyState {
+	castFunc := func(typ interface{}) BACnetLifeSafetyState {
+		if sBACnetLifeSafetyState, ok := typ.(BACnetLifeSafetyState); ok {
+			return sBACnetLifeSafetyState
+		}
+		return 0
+	}
+	return castFunc(structType)
+}
+
+func (m BACnetLifeSafetyState) GetLengthInBits() uint16 {
+	return 16
+}
+
+func (m BACnetLifeSafetyState) GetLengthInBytes() uint16 {
+	return m.GetLengthInBits() / 8
+}
+
+func BACnetLifeSafetyStateParse(readBuffer utils.ReadBuffer) (BACnetLifeSafetyState, error) {
+	val, err := readBuffer.ReadUint16("BACnetLifeSafetyState", 16)
+	if err != nil {
+		return 0, nil
+	}
+	return BACnetLifeSafetyStateByValue(val), nil
+}
+
+func (e BACnetLifeSafetyState) Serialize(writeBuffer utils.WriteBuffer) error {
+	return writeBuffer.WriteUint16("BACnetLifeSafetyState", 16, uint16(e), utils.WithAdditionalStringRepresentation(e.name()))
+}
+
+func (e BACnetLifeSafetyState) name() string {
+	switch e {
+	case BACnetLifeSafetyState_QUIET:
+		return "QUIET"
+	case BACnetLifeSafetyState_PRE_ALARM:
+		return "PRE_ALARM"
+	case BACnetLifeSafetyState_TEST_ACTIVE:
+		return "TEST_ACTIVE"
+	case BACnetLifeSafetyState_TEST_FAULT:
+		return "TEST_FAULT"
+	case BACnetLifeSafetyState_TEST_FAULT_ALARM:
+		return "TEST_FAULT_ALARM"
+	case BACnetLifeSafetyState_HOLDUP:
+		return "HOLDUP"
+	case BACnetLifeSafetyState_DURESS:
+		return "DURESS"
+	case BACnetLifeSafetyState_TAMPER_ALARM:
+		return "TAMPER_ALARM"
+	case BACnetLifeSafetyState_ABNORMAL:
+		return "ABNORMAL"
+	case BACnetLifeSafetyState_EMERGENCY_POWER:
+		return "EMERGENCY_POWER"
+	case BACnetLifeSafetyState_DELAYED:
+		return "DELAYED"
+	case BACnetLifeSafetyState_BLOCKED:
+		return "BLOCKED"
+	case BACnetLifeSafetyState_ALARM:
+		return "ALARM"
+	case BACnetLifeSafetyState_LOCAL_ALARM:
+		return "LOCAL_ALARM"
+	case BACnetLifeSafetyState_GENERAL_ALARM:
+		return "GENERAL_ALARM"
+	case BACnetLifeSafetyState_SUPERVISORY:
+		return "SUPERVISORY"
+	case BACnetLifeSafetyState_TEST_SUPERVISORY:
+		return "TEST_SUPERVISORY"
+	case BACnetLifeSafetyState_FAULT:
+		return "FAULT"
+	case BACnetLifeSafetyState_FAULT_PRE_ALARM:
+		return "FAULT_PRE_ALARM"
+	case BACnetLifeSafetyState_FAULT_ALARM:
+		return "FAULT_ALARM"
+	case BACnetLifeSafetyState_NOT_READY:
+		return "NOT_READY"
+	case BACnetLifeSafetyState_ACTIVE:
+		return "ACTIVE"
+	case BACnetLifeSafetyState_TAMPER:
+		return "TAMPER"
+	case BACnetLifeSafetyState_TEST_ALARM:
+		return "TEST_ALARM"
+	}
+	return ""
+}
+
+func (e BACnetLifeSafetyState) String() string {
+	return e.name()
+}
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/StaticHelper.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/StaticHelper.go
index aaea839f5a..b386971220 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/StaticHelper.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/StaticHelper.go
@@ -676,6 +676,13 @@ func MapRejectReason(rawRejectReason uint8, proprietary bool) RejectReason {
 	return RejectReason(rawRejectReason)
 }
 
+func MapBACnetLifeSafetyState(enumerated BACnetApplicationTagEnumerated, proprietary bool) BACnetLifeSafetyState {
+	if proprietary {
+		return 0
+	}
+	return BACnetLifeSafetyState(enumerated.GetActualValue())
+}
+
 func MapBACnetObjectType(rawObjectType BACnetContextTagEnumerated) BACnetObjectType {
 	baCnetObjectType := BACnetObjectTypeByValue(uint16(rawObjectType.GetActualValue()))
 	if baCnetObjectType == 0 {
diff --git a/plc4j/drivers/bacnet/src/main/java/org/apache/plc4x/java/bacnetip/readwrite/utils/StaticHelper.java b/plc4j/drivers/bacnet/src/main/java/org/apache/plc4x/java/bacnetip/readwrite/utils/StaticHelper.java
index 26054eb4b8..868605abc5 100644
--- a/plc4j/drivers/bacnet/src/main/java/org/apache/plc4x/java/bacnetip/readwrite/utils/StaticHelper.java
+++ b/plc4j/drivers/bacnet/src/main/java/org/apache/plc4x/java/bacnetip/readwrite/utils/StaticHelper.java
@@ -1147,6 +1147,11 @@ public class StaticHelper {
         return RejectReason.enumForValue(rawRejectReason);
     }
 
+    public static BACnetLifeSafetyState mapBACnetLifeSafetyState(BACnetApplicationTagEnumerated rawData, boolean proprietary) {
+        if (proprietary) return null;
+        return BACnetLifeSafetyState.enumForValue((int) rawData.getActualValue());
+    }
+
     public static BACnetObjectType mapBACnetObjectType(BACnetContextTagEnumerated rawObjectType) {
         if (rawObjectType == null) return null;
         BACnetObjectType baCnetObjectType = BACnetObjectType.enumForValue((int) rawObjectType.getActualValue());
diff --git a/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/ManualBacNetDecoder.java b/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/ManualBacNetDecoder.java
index 2593b88833..4bb5d6aace 100644
--- a/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/ManualBacNetDecoder.java
+++ b/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/ManualBacNetDecoder.java
@@ -19,17 +19,47 @@
 package org.apache.plc4x.java.bacnetip;
 
 import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.io.HexDump;
+import org.apache.commons.lang3.ArrayUtils;
 import org.apache.plc4x.java.bacnetip.readwrite.BVLC;
+import org.apache.plc4x.java.spi.generation.ParseException;
 import org.apache.plc4x.java.spi.generation.ReadBuffer;
 import org.apache.plc4x.java.spi.generation.ReadBufferByteBased;
 
+import java.util.stream.IntStream;
+
+import static org.apache.plc4x.java.bacnetip.Utils.tryParseBytes;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
 public class ManualBacNetDecoder {
 
     public static void main(String[] args) throws Exception {
-        final byte[] bytes = Hex.decodeHex("810a001b010030030e0c020000011e294c39014ec4020000014f1f");
-        ReadBuffer readBuffer = new ReadBufferByteBased(bytes);
-        final BVLC packet = BVLC.staticParse(readBuffer);
-        System.out.println(packet);
+        int[] rawBytesAsInts = new int[]{
+            /*00000000*/ 0x81, 0x0A, 0x01, 0x68, 0x01, 0x00, 0x30, 0x41, 0x0E, 0x0C, 0x05, 0x40, 0x00, 0x01, 0x1E, 0x29, //...h..0A...@...)
+            /*00000010*/ 0x4B, 0x4E, 0xC4, 0x05, 0x40, 0x00, 0x01, 0x4F, 0x29, 0x4D, 0x4E, 0x74, 0x00, 0x4C, 0x50, 0x31, //KN..@..O)MNt.LP1
+            /*00000020*/ 0x4F, 0x29, 0x4F, 0x4E, 0x91, 0x15, 0x4F, 0x29, 0x55, 0x4E, 0x91, 0x00, 0x4F, 0x29, 0x6F, 0x4E, //O)ON..O)UN..O)oN
+            /*00000030*/ 0x82, 0x04, 0x00, 0x4F, 0x29, 0x24, 0x4E, 0x91, 0x00, 0x4F, 0x29, 0x67, 0x4E, 0x91, 0x00, 0x4F, //...O)$N..O)gN..O
+            /*00000040*/ 0x29, 0x51, 0x4E, 0x10, 0x4F, 0x29, 0xA0, 0x4E, 0x91, 0x01, 0x4F, 0x29, 0xAF, 0x4E, 0x91, 0x00, //)QN.O).N..O).N..
+            /*00000050*/ 0x91, 0x01, 0x91, 0x02, 0x91, 0x03, 0x91, 0x04, 0x91, 0x05, 0x91, 0x06, 0x91, 0x07, 0x91, 0x08, //................
+            /*00000060*/ 0x91, 0x09, 0x91, 0x0A, 0x91, 0x0B, 0x91, 0x0C, 0x91, 0x0D, 0x91, 0x0E, 0x4F, 0x29, 0xA3, 0x4E, //............O).N
+            /*00000070*/ 0x91, 0x00, 0x4F, 0x29, 0xA1, 0x4E, 0x91, 0x00, 0x4F, 0x29, 0x1C, 0x4E, 0x75, 0x19, 0x00, 0x54, //..O).N..O).Nu..T
+            /*00000080*/ 0x65, 0x73, 0x74, 0x20, 0x4C, 0x69, 0x66, 0x65, 0x20, 0x53, 0x61, 0x66, 0x65, 0x74, 0x79, 0x20, //est Life Safety
+            /*00000090*/ 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x31, 0x4F, 0x29, 0x1F, 0x4E, 0x75, 0x1B, 0x00, 0x53, 0x69, //Point 1O).Nu..Si
+            /*000000A0*/ 0x6D, 0x75, 0x6C, 0x61, 0x74, 0x65, 0x64, 0x20, 0x53, 0x65, 0x6E, 0x73, 0x6F, 0x72, 0x20, 0x75, //mulated Sensor u
+            /*000000B0*/ 0x73, 0x69, 0x6E, 0x67, 0x20, 0x50, 0x47, 0x37, 0x4F, 0x29, 0xA4, 0x4E, 0x91, 0x00, 0x4F, 0x29, //sing PG7O).N..O)
+            /*000000C0*/ 0xA8, 0x4E, 0x75, 0x19, 0x00, 0x30, 0x2D, 0x4F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x2D, 0x4C, 0x69, //.Nu..0-Object-Li
+            /*000000D0*/ 0x66, 0x65, 0x53, 0x61, 0x66, 0x65, 0x74, 0x79, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x4F, 0x29, 0x9E, //feSafetyPointO).
+            /*000000E0*/ 0x4E, 0x91, 0x00, 0x4F, 0x29, 0xA2, 0x4E, 0x21, 0x00, 0x4F, 0x29, 0x9C, 0x4E, 0x44, 0x00, 0x00, //N..O).N!.O).ND..
+            /*000000F0*/ 0x00, 0x00, 0x4F, 0x29, 0x75, 0x4E, 0x91, 0x5F, 0x4F, 0x29, 0x9F, 0x4E, 0x0C, 0x02, 0x00, 0x0F, //..O)uN._O).N....
+            /*00000100*/ 0xA0, 0x1C, 0x05, 0x80, 0x00, 0x01, 0x1C, 0x05, 0x80, 0x00, 0x01, 0x4F, 0x29, 0x71, 0x4E, 0x21, //...........O)qN!
+            /*00000110*/ 0x05, 0x4F, 0x29, 0x11, 0x4E, 0x21, 0x01, 0x4F, 0x29, 0x07, 0x4E, 0x91, 0x02, 0x91, 0x05, 0x91, //.O).N!.O).N.....
+            /*00000120*/ 0x09, 0x91, 0x0C, 0x91, 0x0F, 0x91, 0x14, 0x91, 0x15, 0x4F, 0x29, 0x27, 0x4E, 0x91, 0x03, 0x91, //.........O)'N...
+            /*00000130*/ 0x0B, 0x4F, 0x29, 0xA6, 0x4E, 0x91, 0x08, 0x91, 0x0D, 0x91, 0x0E, 0x4F, 0x29, 0x23, 0x4E, 0x82, //.O).N......O)#N.
+            /*00000140*/ 0x05, 0x00, 0x4F, 0x29, 0x00, 0x4E, 0x82, 0x05, 0xE0, 0x4F, 0x29, 0x48, 0x4E, 0x91, 0x00, 0x4F, //..O).N...O)HN..O
+            /*00000150*/ 0x29, 0x82, 0x4E, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, 0x19, 0x00, 0x2E, 0xA4, 0xFF, 0xFF, 0xFF, 0xFF, //).N.............
+            /*00000160*/ 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0x2F, 0x4F, 0x1F,                                                 //...../O.
+        };
+        tryParseBytes(rawBytesAsInts,0, true);
     }
 
 }
diff --git a/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/RandomPackagesTest.java b/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/RandomPackagesTest.java
index 71cc3eaba8..12457677fa 100644
--- a/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/RandomPackagesTest.java
+++ b/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/RandomPackagesTest.java
@@ -280,9 +280,9 @@ public class RandomPackagesTest {
                     assertEquals(BACnetObjectType.LIFE_SAFETY_ZONE, baCnetServiceAckReadProperty.getObjectIdentifier().getObjectType());
                     assertEquals(1, baCnetServiceAckReadProperty.getObjectIdentifier().getInstanceNumber());
                     assertEquals(BACnetPropertyIdentifier.ZONE_MEMBERS, baCnetServiceAckReadProperty.getPropertyIdentifier().getPropertyIdentifier());
-                    BACnetConstructedDataLifeSafetyZoneMembers baCnetConstructedDataLifeSafetyZoneMembers = (BACnetConstructedDataLifeSafetyZoneMembers) baCnetServiceAckReadProperty.getValues();
+                    BACnetConstructedDataZoneMembers baCnetConstructedDataZoneMembers = (BACnetConstructedDataZoneMembers) baCnetServiceAckReadProperty.getValues();
 
-                    List<BACnetDeviceObjectReference> members = baCnetConstructedDataLifeSafetyZoneMembers.getMembers();
+                    List<BACnetDeviceObjectReference> members = baCnetConstructedDataZoneMembers.getMembers();
                     assertThat(members.get(0)).extracting(BACnetDeviceObjectReference::getObjectIdentifier).extracting("objectType", "instanceNumber").contains(BACnetObjectType.LIFE_SAFETY_ZONE, 3L);
                     assertThat(members.get(1)).extracting(BACnetDeviceObjectReference::getObjectIdentifier).extracting("objectType", "instanceNumber").contains(BACnetObjectType.LIFE_SAFETY_ZONE, 4L);
                     assertThat(members.get(2)).extracting(BACnetDeviceObjectReference::getObjectIdentifier).extracting("objectType", "instanceNumber").contains(BACnetObjectType.LIFE_SAFETY_ZONE, 5L);
@@ -324,9 +324,9 @@ public class RandomPackagesTest {
                     assertEquals(BACnetObjectType.LIFE_SAFETY_ZONE, baCnetServiceAckReadProperty.getObjectIdentifier().getObjectType());
                     assertEquals(1, baCnetServiceAckReadProperty.getObjectIdentifier().getInstanceNumber());
                     assertEquals(BACnetPropertyIdentifier.MEMBER_OF, baCnetServiceAckReadProperty.getPropertyIdentifier().getPropertyIdentifier());
-                    BACnetConstructedDataLifeSafetyZoneMemberOf baCnetConstructedDataLifeSafetyZoneMemberOf = (BACnetConstructedDataLifeSafetyZoneMemberOf) baCnetServiceAckReadProperty.getValues();
+                    BACnetConstructedDataMemberOf baCnetConstructedDataMemberOf = (BACnetConstructedDataMemberOf) baCnetServiceAckReadProperty.getValues();
 
-                    List<BACnetDeviceObjectReference> zones = baCnetConstructedDataLifeSafetyZoneMemberOf.getZones();
+                    List<BACnetDeviceObjectReference> zones = baCnetConstructedDataMemberOf.getZones();
                     assertThat(zones.get(0)).extracting(BACnetDeviceObjectReference::getObjectIdentifier).extracting("objectType", "instanceNumber").contains(BACnetObjectType.LIFE_SAFETY_ZONE, 1L);
                 })
         );
diff --git a/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/TrickyPackagesTest.java b/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/TrickyPackagesTest.java
index d9ee13cef2..3eca552866 100644
--- a/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/TrickyPackagesTest.java
+++ b/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/TrickyPackagesTest.java
@@ -18,20 +18,14 @@
  */
 package org.apache.plc4x.java.bacnetip;
 
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.plc4x.java.bacnetip.readwrite.BVLC;
-import org.apache.plc4x.java.spi.generation.ParseException;
-import org.apache.plc4x.java.spi.generation.ReadBufferByteBased;
 import org.junit.jupiter.api.Test;
 
-import java.util.stream.IntStream;
 
-import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.apache.plc4x.java.bacnetip.Utils.PAYLOAD_START_INDEX;
+import static org.apache.plc4x.java.bacnetip.Utils.tryParseBytes;
 
 public class TrickyPackagesTest {
 
-    public static final boolean dumpPackages = false;
-
     // from plugfest-tridium-1.pcap
     @Test
     public void testTridium255() throws Exception {
@@ -101,7 +95,7 @@ public class TrickyPackagesTest {
             /*0150*/   0x01, 0x59, 0x05, 0x69, 0x01, 0x79, 0x07, 0x8e, 0x0a, 0x26, 0xe1, 0x19, 0x00, 0x2a, 0x25, 0xb9,
             /*0160*/   0x39, 0x00, 0x49, 0x00, 0x8f, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x1f,
         };
-        tryParseBytes(rawBytesAsInts);
+        tryParseBytes(rawBytesAsInts, PAYLOAD_START_INDEX);
     }
 
     // from TrendLogMultipleReadRangeSimple.pcap
@@ -236,16 +230,9 @@ public class TrickyPackagesTest {
             /*000000f0*/  0x44, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x29, 0x1b, 0x4e, 0x91, 0x49, 0x4f, 0x29, 0x0e, 0x4e, 0x44,  //|D....O).N.IO).ND|
             /*00000100*/  0x00, 0x00, 0x00, 0x00, 0x4f, 0x29, 0x3d, 0x4e, 0x44, 0x42, 0xc8, 0x00, 0x00, 0x4f, 0x29, 0x44,  //|....O)=NDB...O)D|
             /*00000110*/  0x4e, 0x44, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x29, 0x16, 0x4e, 0x44, 0x00, 0x00, 0x00, 0x00, 0x4f,  //|ND....O).ND....O|
-            /*00000120*/  0x1f,                                                //|.|
+            /*00000120*/  0x1f,                                                                                            //|.|
         };
         tryParseBytes(rawBytesAsInts);
     }
 
-    private void tryParseBytes(int[] rawBytesAsInts) throws ParseException {
-        var rawBytes = (byte[]) ArrayUtils.toPrimitive(IntStream.of(rawBytesAsInts).boxed().map(Integer::byteValue).toArray(Byte[]::new));
-        rawBytes = ArrayUtils.subarray(rawBytes, 42, rawBytes.length);
-        BVLC bvlc = BVLC.staticParse(new ReadBufferByteBased(rawBytes));
-        assertNotNull(bvlc);
-        if (dumpPackages) System.out.println(bvlc);
-    }
 }
diff --git a/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/Utils.java b/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/Utils.java
new file mode 100644
index 0000000000..8904593226
--- /dev/null
+++ b/plc4j/drivers/bacnet/src/test/java/org/apache/plc4x/java/bacnetip/Utils.java
@@ -0,0 +1,32 @@
+package org.apache.plc4x.java.bacnetip;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.plc4x.java.bacnetip.readwrite.BVLC;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBufferByteBased;
+
+import java.util.stream.IntStream;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class Utils {
+    static final boolean DUMP_PACKAGES = false;
+
+    static int PAYLOAD_START_INDEX = 42;
+
+    static void tryParseBytes(int[] rawBytesAsInts) throws ParseException {
+        tryParseBytes(rawBytesAsInts, PAYLOAD_START_INDEX);
+    }
+
+    static void tryParseBytes(int[] rawBytesAsInts, int startIndex) throws ParseException {
+        tryParseBytes(rawBytesAsInts, PAYLOAD_START_INDEX, DUMP_PACKAGES);
+    }
+
+    static void tryParseBytes(int[] rawBytesAsInts, int startIndex, boolean dumpPackages) throws ParseException {
+        var rawBytes = (byte[]) ArrayUtils.toPrimitive(IntStream.of(rawBytesAsInts).boxed().map(Integer::byteValue).toArray(Byte[]::new));
+        rawBytes = ArrayUtils.subarray(rawBytes, startIndex, rawBytes.length);
+        BVLC bvlc = BVLC.staticParse(new ReadBufferByteBased(rawBytes));
+        assertNotNull(bvlc);
+        if (dumpPackages) System.out.println(bvlc);
+    }
+}
diff --git a/plc4j/drivers/bacnet/src/test/resources/logback-test.xml b/plc4j/drivers/bacnet/src/test/resources/logback-test.xml
index 8c5833b21c..90e5d8ed46 100644
--- a/plc4j/drivers/bacnet/src/test/resources/logback-test.xml
+++ b/plc4j/drivers/bacnet/src/test/resources/logback-test.xml
@@ -25,7 +25,10 @@
     </encoder>
   </appender>
 
-  <root level="error">
+  <!-- TODO: why doesn't this work? log won't be switched off-->
+  <logger name="org.apache.plc4x.java.bacnetip.RandomPackagesTest" level="OFF"/>
+
+  <root level="ERROR">
     <appender-ref ref="STDOUT" />
   </root>
 
diff --git a/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec b/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
index d0a7f353be..318a7c043a 100644
--- a/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
+++ b/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
@@ -1842,6 +1842,43 @@
     ]
 ]
 
+[type BACnetConstructedDataLifeSafetyAlarmValuesEntry
+    [optional BACnetApplicationTagEnumerated
+                        rawData                                                                                 ]
+    [virtual  bit       isLifeSafetyStateProprietary 'rawData.actualValue > 255'                                ]
+    [virtual  BACnetLifeSafetyState
+                        lifeSafetyState 
+                            'STATIC_CALL("mapBACnetLifeSafetyState", rawData, isLifeSafetyStateProprietary)'    ]
+    [virtual  uint 16    lifeSafetyStateProprietary 'isLifeSafetyStateProprietary?rawData.actualValue:0'        ]
+]
+
+[enum uint 16 BACnetLifeSafetyState
+    ['0'    QUIET]
+    ['1'    PRE_ALARM]
+    ['2'    ALARM]
+    ['3'    FAULT]
+    ['4'    FAULT_PRE_ALARM]
+    ['5'    FAULT_ALARM]
+    ['6'    NOT_READY]
+    ['7'    ACTIVE]
+    ['8'    TAMPER]
+    ['9'    TEST_ALARM]
+    ['10'   TEST_ACTIVE]
+    ['11'   TEST_FAULT]
+    ['12'   TEST_FAULT_ALARM]
+    ['13'   HOLDUP]
+    ['14'   DURESS]
+    ['15'   TAMPER_ALARM]
+    ['16'   ABNORMAL]
+    ['17'   EMERGENCY_POWER]
+    ['18'   DELAYED]
+    ['19'   BLOCKED]
+    ['20'   LOCAL_ALARM]
+    ['21'   GENERAL_ALARM]
+    ['22'   SUPERVISORY]
+    ['23'   TEST_SUPERVISORY]
+]
+
 // TODO: this is a enum so we should build a static call which maps a enum (could be solved by using only the tag header with a length validation and the enum itself)
 [type BACnetStatusFlags(uint 8 tagNumber)
     [simple BACnetContextTagBitString('tagNumber', 'BACnetDataType.BIT_STRING')
@@ -1857,8 +1894,7 @@
 // TODO: fixme... this is only in context a context tag... otherwise it can be and application tag
 [type BACnetAction(uint 8 tagNumber)
     [optional   BACnetContextTagEnumerated('tagNumber', 'BACnetDataType.ENUMERATED')
-                rawData
-    ]
+                rawData                                                           ]
     [virtual    bit isDirect         'rawData != null && rawData.actualValue == 0']
     [virtual    bit isReverse        'rawData != null && rawData.actualValue == 1']
 ]
@@ -2394,26 +2430,6 @@
     [virtual    BACnetPropertyIdentifier
                         propertyIdentifierEnum  'propertyIdentifierArgument.propertyIdentifier']
     [typeSwitch objectType, propertyIdentifierEnum
-        /////
-        // LifeSafetyZone
-
-        ['LIFE_SAFETY_ZONE', 'ZONE_MEMBERS'             BACnetConstructedDataLifeSafetyZoneMembers
-            [array  BACnetDeviceObjectReference
-                        members
-                    terminated
-                    'STATIC_CALL("isBACnetConstructedDataClosingTag", readBuffer, false, tagNumber)'            ]
-        ]
-        ['LIFE_SAFETY_ZONE', 'MEMBER_OF'                BACnetConstructedDataLifeSafetyZoneMemberOf
-            [array  BACnetDeviceObjectReference
-                        zones
-                            terminated
-                            'STATIC_CALL("isBACnetConstructedDataClosingTag", readBuffer, false, tagNumber)'    ]
-        ]
-        //
-        /////
-
-        /////
-        // Generic Mapping
         //[*, 'ABSENTEE_LIMIT'                          BACnetConstructedDataAbsenteeLimit [validation    '1 == 2'    "TODO: implement me ABSENTEE_LIMIT BACnetConstructedDataAbsenteeLimit"]]
         //[*, 'ACCEPTED_MODES'                          BACnetConstructedDataAcceptedModes [validation    '1 == 2'    "TODO: implement me ACCEPTED_MODES BACnetConstructedDataAcceptedModes"]]
         //[*, 'ACCESS_ALARM_EVENTS'                     BACnetConstructedDataAccessAlarmEvents [validation    '1 == 2'    "TODO: implement me ACCESS_ALARM_EVENTS BACnetConstructedDataAccessAlarmEvents"]]
@@ -2663,7 +2679,11 @@
         //[*, 'LAST_RESTORE_TIME'                       BACnetConstructedDataLastRestoreTime [validation    '1 == 2'    "TODO: implement me LAST_RESTORE_TIME BACnetConstructedDataLastRestoreTime"]]
         //[*, 'LAST_STATE_CHANGE'                       BACnetConstructedDataLastStateChange [validation    '1 == 2'    "TODO: implement me LAST_STATE_CHANGE BACnetConstructedDataLastStateChange"]]
         //[*, 'LAST_USE_TIME'                           BACnetConstructedDataLastUseTime [validation    '1 == 2'    "TODO: implement me LAST_USE_TIME BACnetConstructedDataLastUseTime"]]
-        //[*, 'LIFE_SAFETY_ALARM_VALUES'                BACnetConstructedDataLifeSafetyAlarmValues [validation    '1 == 2'    "TODO: implement me LIFE_SAFETY_ALARM_VALUES BACnetConstructedDataLifeSafetyAlarmValues"]]
+        [*, 'LIFE_SAFETY_ALARM_VALUES'                BACnetConstructedDataLifeSafetyAlarmValues
+            [array    BACnetConstructedDataLifeSafetyAlarmValuesEntry
+                            alarmValues              terminated
+                                'STATIC_CALL("isBACnetConstructedDataClosingTag", readBuffer, false, tagNumber)']
+        ]
         //[*, 'LIGHTING_COMMAND'                        BACnetConstructedDataLightingCommand [validation    '1 == 2'    "TODO: implement me LIGHTING_COMMAND BACnetConstructedDataLightingCommand"]]
         //[*, 'LIGHTING_COMMAND_DEFAULT_PRIORITY'       BACnetConstructedDataLightingCommandDefaultPriority [validation    '1 == 2'    "TODO: implement me LIGHTING_COMMAND_DEFAULT_PRIORITY BACnetConstructedDataLightingCommandDefaultPriority"]]
         //[*, 'LIMIT_ENABLE'                            BACnetConstructedDataLimitEnable [validation    '1 == 2'    "TODO: implement me LIMIT_ENABLE BACnetConstructedDataLimitEnable"]]
@@ -2909,8 +2929,6 @@
                             data                    terminated
                                 'STATIC_CALL("isBACnetConstructedDataClosingTag", readBuffer, false, tagNumber)']
         ]
-        //
-        /////
     ]
     [simple       BACnetClosingTag('tagNumber', 'BACnetDataType.CLOSING_TAG')
                         closingTag                                                                              ]