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/07/28 12:46:41 UTC

[plc4x] 03/03: fix(cbus): fixed level reporting for ExtendedFormatStatusReply

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

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

commit 0b713c67bbb6c1fc86a01cd18f11a71a20536400
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Thu Jul 28 14:46:31 2022 +0200

    fix(cbus): fixed level reporting for ExtendedFormatStatusReply
---
 plc4go/internal/cbus/Reader.go                     |  20 +-
 plc4go/protocols/cbus/readwrite/ParserHelper.go    |   2 +
 plc4go/protocols/cbus/readwrite/XmlParserHelper.go |   2 +
 .../readwrite/model/ExtendedFormatStatusReply.go   | 123 +++++++-
 .../cbus/readwrite/model/LevelInformation.go       | 344 +++++++++++++++++++++
 .../cbus/readwrite/model/LevelInformationAbsent.go | 180 +++++++++++
 .../readwrite/model/LevelInformationCorrupted.go   | 268 ++++++++++++++++
 .../readwrite/model/LevelInformationNibblePair.go  | 323 +++++++++++++++++++
 .../cbus/readwrite/model/LevelInformationNormal.go | 264 ++++++++++++++++
 .../org/apache/plc4x/java/cbus/ReferenceTest.java  |   2 +-
 .../src/main/resources/protocols/cbus/c-bus.mspec  |  57 +++-
 .../server/cbus/protocol/CBusServerAdapter.java    |   8 +-
 12 files changed, 1572 insertions(+), 21 deletions(-)

diff --git a/plc4go/internal/cbus/Reader.go b/plc4go/internal/cbus/Reader.go
index 6eaa35c20..ccab01381 100644
--- a/plc4go/internal/cbus/Reader.go
+++ b/plc4go/internal/cbus/Reader.go
@@ -163,10 +163,22 @@ func (m *Reader) Read(readRequest model.PlcReadRequest) <-chan model.PlcReadRequ
 							blockStart := reply.GetReply().GetBlockStart()
 							// TODO: verify application... this should be the same
 							_ = blockStart
-							statusBytes := reply.GetReply().GetStatusBytes()
-							addResponseCode(fieldNameCopy, model.PlcResponseCode_OK)
-							// TODO: how should we serialize that???
-							addPlcValue(fieldNameCopy, values2.NewPlcSTRING(fmt.Sprintf("%s", statusBytes)))
+							switch coding {
+							case readWriteModel.StatusCoding_BINARY_BY_THIS_SERIAL_INTERFACE:
+								fallthrough
+							case readWriteModel.StatusCoding_BINARY_BY_ELSEWHERE:
+								statusBytes := reply.GetReply().GetStatusBytes()
+								addResponseCode(fieldNameCopy, model.PlcResponseCode_OK)
+								// TODO: how should we serialize that???
+								addPlcValue(fieldNameCopy, values2.NewPlcSTRING(fmt.Sprintf("%s", statusBytes)))
+							case readWriteModel.StatusCoding_LEVEL_BY_THIS_SERIAL_INTERFACE:
+								fallthrough
+							case readWriteModel.StatusCoding_LEVEL_BY_ELSEWHERE:
+								levelInformation := reply.GetReply().GetLevelInformation()
+								addResponseCode(fieldNameCopy, model.PlcResponseCode_OK)
+								// TODO: how should we serialize that???
+								addPlcValue(fieldNameCopy, values2.NewPlcSTRING(fmt.Sprintf("%s", levelInformation)))
+							}
 						case readWriteModel.EncodedReplyCALReplyExactly:
 							calData := reply.GetCalReply().GetCalData()
 							addResponseCode(fieldNameCopy, model.PlcResponseCode_OK)
diff --git a/plc4go/protocols/cbus/readwrite/ParserHelper.go b/plc4go/protocols/cbus/readwrite/ParserHelper.go
index 382deb3a6..76039241c 100644
--- a/plc4go/protocols/cbus/readwrite/ParserHelper.go
+++ b/plc4go/protocols/cbus/readwrite/ParserHelper.go
@@ -151,6 +151,8 @@ func (m CbusParserHelper) Parse(typeName string, arguments []string, io utils.Re
 		return model.StandardFormatStatusReplyParse(io)
 	case "ResponseTermination":
 		return model.ResponseTerminationParse(io)
+	case "LevelInformation":
+		return model.LevelInformationParse(io)
 	case "SALData":
 		applicationId, _ := model.ApplicationIdByName(arguments[0])
 		return model.SALDataParse(io, applicationId)
diff --git a/plc4go/protocols/cbus/readwrite/XmlParserHelper.go b/plc4go/protocols/cbus/readwrite/XmlParserHelper.go
index 0b5ae2192..69d4d0d2b 100644
--- a/plc4go/protocols/cbus/readwrite/XmlParserHelper.go
+++ b/plc4go/protocols/cbus/readwrite/XmlParserHelper.go
@@ -170,6 +170,8 @@ func (m CbusXmlParserHelper) Parse(typeName string, xmlString string, parserArgu
 		return model.StandardFormatStatusReplyParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
 	case "ResponseTermination":
 		return model.ResponseTerminationParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
+	case "LevelInformation":
+		return model.LevelInformationParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
 	case "SALData":
 		applicationId, _ := model.ApplicationIdByName(parserArguments[0])
 		return model.SALDataParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)), applicationId)
diff --git a/plc4go/protocols/cbus/readwrite/model/ExtendedFormatStatusReply.go b/plc4go/protocols/cbus/readwrite/model/ExtendedFormatStatusReply.go
index dd9f58bac..9314c2250 100644
--- a/plc4go/protocols/cbus/readwrite/model/ExtendedFormatStatusReply.go
+++ b/plc4go/protocols/cbus/readwrite/model/ExtendedFormatStatusReply.go
@@ -40,6 +40,12 @@ type ExtendedFormatStatusReply interface {
 	GetBlockStart() uint8
 	// GetStatusBytes returns StatusBytes (property field)
 	GetStatusBytes() []StatusByte
+	// GetLevelInformation returns LevelInformation (property field)
+	GetLevelInformation() []LevelInformation
+	// GetNumberOfStatusBytes returns NumberOfStatusBytes (virtual field)
+	GetNumberOfStatusBytes() uint8
+	// GetNumberOfLevelInformation returns NumberOfLevelInformation (virtual field)
+	GetNumberOfLevelInformation() uint8
 }
 
 // ExtendedFormatStatusReplyExactly can be used when we want exactly this type and not a type which fulfills ExtendedFormatStatusReply.
@@ -51,11 +57,12 @@ type ExtendedFormatStatusReplyExactly interface {
 
 // _ExtendedFormatStatusReply is the data-structure of this message
 type _ExtendedFormatStatusReply struct {
-	StatusHeader ExtendedStatusHeader
-	Coding       StatusCoding
-	Application  ApplicationIdContainer
-	BlockStart   uint8
-	StatusBytes  []StatusByte
+	StatusHeader     ExtendedStatusHeader
+	Coding           StatusCoding
+	Application      ApplicationIdContainer
+	BlockStart       uint8
+	StatusBytes      []StatusByte
+	LevelInformation []LevelInformation
 }
 
 ///////////////////////////////////////////////////////////
@@ -83,14 +90,39 @@ func (m *_ExtendedFormatStatusReply) GetStatusBytes() []StatusByte {
 	return m.StatusBytes
 }
 
+func (m *_ExtendedFormatStatusReply) GetLevelInformation() []LevelInformation {
+	return m.LevelInformation
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for virtual fields.
+///////////////////////
+
+func (m *_ExtendedFormatStatusReply) GetNumberOfStatusBytes() uint8 {
+	return uint8(utils.InlineIf(bool(bool(bool((m.GetCoding()) == (StatusCoding_BINARY_BY_THIS_SERIAL_INTERFACE))) || bool(bool((m.GetCoding()) == (StatusCoding_BINARY_BY_ELSEWHERE)))), func() interface{} {
+		return uint8(uint8(uint8(m.GetStatusHeader().GetNumberOfCharacterPairs()) - uint8(uint8(3))))
+	}, func() interface{} { return uint8(uint8(uint8(0))) }).(uint8))
+}
+
+func (m *_ExtendedFormatStatusReply) GetNumberOfLevelInformation() uint8 {
+	return uint8(utils.InlineIf(bool(bool(bool((m.GetCoding()) == (StatusCoding_LEVEL_BY_THIS_SERIAL_INTERFACE))) || bool(bool((m.GetCoding()) == (StatusCoding_LEVEL_BY_ELSEWHERE)))), func() interface{} {
+		return uint8(uint8(uint8(uint8(uint8(m.GetStatusHeader().GetNumberOfCharacterPairs())-uint8(uint8(3)))) / uint8(uint8(2))))
+	}, func() interface{} { return uint8(uint8(uint8(0))) }).(uint8))
+}
+
 ///////////////////////
 ///////////////////////
 ///////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////
 
 // NewExtendedFormatStatusReply factory function for _ExtendedFormatStatusReply
-func NewExtendedFormatStatusReply(statusHeader ExtendedStatusHeader, coding StatusCoding, application ApplicationIdContainer, blockStart uint8, statusBytes []StatusByte) *_ExtendedFormatStatusReply {
-	return &_ExtendedFormatStatusReply{StatusHeader: statusHeader, Coding: coding, Application: application, BlockStart: blockStart, StatusBytes: statusBytes}
+func NewExtendedFormatStatusReply(statusHeader ExtendedStatusHeader, coding StatusCoding, application ApplicationIdContainer, blockStart uint8, statusBytes []StatusByte, levelInformation []LevelInformation) *_ExtendedFormatStatusReply {
+	return &_ExtendedFormatStatusReply{StatusHeader: statusHeader, Coding: coding, Application: application, BlockStart: blockStart, StatusBytes: statusBytes, LevelInformation: levelInformation}
 }
 
 // Deprecated: use the interface for direct cast
@@ -127,6 +159,10 @@ func (m *_ExtendedFormatStatusReply) GetLengthInBitsConditional(lastItem bool) u
 	// Simple field (blockStart)
 	lengthInBits += 8
 
+	// A virtual field doesn't have any in- or output.
+
+	// A virtual field doesn't have any in- or output.
+
 	// Array field
 	if len(m.StatusBytes) > 0 {
 		for i, element := range m.StatusBytes {
@@ -135,6 +171,14 @@ func (m *_ExtendedFormatStatusReply) GetLengthInBitsConditional(lastItem bool) u
 		}
 	}
 
+	// Array field
+	if len(m.LevelInformation) > 0 {
+		for i, element := range m.LevelInformation {
+			last := i == len(m.LevelInformation)-1
+			lengthInBits += element.(interface{ GetLengthInBitsConditional(bool) uint16 }).GetLengthInBitsConditional(last)
+		}
+	}
+
 	return lengthInBits
 }
 
@@ -197,18 +241,32 @@ func ExtendedFormatStatusReplyParse(readBuffer utils.ReadBuffer) (ExtendedFormat
 	}
 	blockStart := _blockStart
 
+	// Virtual field
+	_numberOfStatusBytes := utils.InlineIf(bool(bool(bool((coding) == (StatusCoding_BINARY_BY_THIS_SERIAL_INTERFACE))) || bool(bool((coding) == (StatusCoding_BINARY_BY_ELSEWHERE)))), func() interface{} {
+		return uint8(uint8(uint8(statusHeader.GetNumberOfCharacterPairs()) - uint8(uint8(3))))
+	}, func() interface{} { return uint8(uint8(uint8(0))) }).(uint8)
+	numberOfStatusBytes := uint8(_numberOfStatusBytes)
+	_ = numberOfStatusBytes
+
+	// Virtual field
+	_numberOfLevelInformation := utils.InlineIf(bool(bool(bool((coding) == (StatusCoding_LEVEL_BY_THIS_SERIAL_INTERFACE))) || bool(bool((coding) == (StatusCoding_LEVEL_BY_ELSEWHERE)))), func() interface{} {
+		return uint8(uint8(uint8(uint8(uint8(statusHeader.GetNumberOfCharacterPairs())-uint8(uint8(3)))) / uint8(uint8(2))))
+	}, func() interface{} { return uint8(uint8(uint8(0))) }).(uint8)
+	numberOfLevelInformation := uint8(_numberOfLevelInformation)
+	_ = numberOfLevelInformation
+
 	// Array field (statusBytes)
 	if pullErr := readBuffer.PullContext("statusBytes", utils.WithRenderAsList(true)); pullErr != nil {
 		return nil, errors.Wrap(pullErr, "Error pulling for statusBytes")
 	}
 	// Count array
-	statusBytes := make([]StatusByte, uint16(statusHeader.GetNumberOfCharacterPairs())-uint16(uint16(3)))
+	statusBytes := make([]StatusByte, numberOfStatusBytes)
 	// This happens when the size is set conditional to 0
 	if len(statusBytes) == 0 {
 		statusBytes = nil
 	}
 	{
-		for curItem := uint16(0); curItem < uint16(uint16(statusHeader.GetNumberOfCharacterPairs())-uint16(uint16(3))); curItem++ {
+		for curItem := uint16(0); curItem < uint16(numberOfStatusBytes); curItem++ {
 			_item, _err := StatusByteParse(readBuffer)
 			if _err != nil {
 				return nil, errors.Wrap(_err, "Error parsing 'statusBytes' field of ExtendedFormatStatusReply")
@@ -220,12 +278,35 @@ func ExtendedFormatStatusReplyParse(readBuffer utils.ReadBuffer) (ExtendedFormat
 		return nil, errors.Wrap(closeErr, "Error closing for statusBytes")
 	}
 
+	// Array field (levelInformation)
+	if pullErr := readBuffer.PullContext("levelInformation", utils.WithRenderAsList(true)); pullErr != nil {
+		return nil, errors.Wrap(pullErr, "Error pulling for levelInformation")
+	}
+	// Count array
+	levelInformation := make([]LevelInformation, numberOfLevelInformation)
+	// This happens when the size is set conditional to 0
+	if len(levelInformation) == 0 {
+		levelInformation = nil
+	}
+	{
+		for curItem := uint16(0); curItem < uint16(numberOfLevelInformation); curItem++ {
+			_item, _err := LevelInformationParse(readBuffer)
+			if _err != nil {
+				return nil, errors.Wrap(_err, "Error parsing 'levelInformation' field of ExtendedFormatStatusReply")
+			}
+			levelInformation[curItem] = _item.(LevelInformation)
+		}
+	}
+	if closeErr := readBuffer.CloseContext("levelInformation", utils.WithRenderAsList(true)); closeErr != nil {
+		return nil, errors.Wrap(closeErr, "Error closing for levelInformation")
+	}
+
 	if closeErr := readBuffer.CloseContext("ExtendedFormatStatusReply"); closeErr != nil {
 		return nil, errors.Wrap(closeErr, "Error closing for ExtendedFormatStatusReply")
 	}
 
 	// Create the instance
-	return NewExtendedFormatStatusReply(statusHeader, coding, application, blockStart, statusBytes), nil
+	return NewExtendedFormatStatusReply(statusHeader, coding, application, blockStart, statusBytes, levelInformation), nil
 }
 
 func (m *_ExtendedFormatStatusReply) Serialize(writeBuffer utils.WriteBuffer) error {
@@ -277,6 +358,14 @@ func (m *_ExtendedFormatStatusReply) Serialize(writeBuffer utils.WriteBuffer) er
 	if _blockStartErr != nil {
 		return errors.Wrap(_blockStartErr, "Error serializing 'blockStart' field")
 	}
+	// Virtual field
+	if _numberOfStatusBytesErr := writeBuffer.WriteVirtual("numberOfStatusBytes", m.GetNumberOfStatusBytes()); _numberOfStatusBytesErr != nil {
+		return errors.Wrap(_numberOfStatusBytesErr, "Error serializing 'numberOfStatusBytes' field")
+	}
+	// Virtual field
+	if _numberOfLevelInformationErr := writeBuffer.WriteVirtual("numberOfLevelInformation", m.GetNumberOfLevelInformation()); _numberOfLevelInformationErr != nil {
+		return errors.Wrap(_numberOfLevelInformationErr, "Error serializing 'numberOfLevelInformation' field")
+	}
 
 	// Array Field (statusBytes)
 	if pushErr := writeBuffer.PushContext("statusBytes", utils.WithRenderAsList(true)); pushErr != nil {
@@ -292,6 +381,20 @@ func (m *_ExtendedFormatStatusReply) Serialize(writeBuffer utils.WriteBuffer) er
 		return errors.Wrap(popErr, "Error popping for statusBytes")
 	}
 
+	// Array Field (levelInformation)
+	if pushErr := writeBuffer.PushContext("levelInformation", utils.WithRenderAsList(true)); pushErr != nil {
+		return errors.Wrap(pushErr, "Error pushing for levelInformation")
+	}
+	for _, _element := range m.GetLevelInformation() {
+		_elementErr := writeBuffer.WriteSerializable(_element)
+		if _elementErr != nil {
+			return errors.Wrap(_elementErr, "Error serializing 'levelInformation' field")
+		}
+	}
+	if popErr := writeBuffer.PopContext("levelInformation", utils.WithRenderAsList(true)); popErr != nil {
+		return errors.Wrap(popErr, "Error popping for levelInformation")
+	}
+
 	if popErr := writeBuffer.PopContext("ExtendedFormatStatusReply"); popErr != nil {
 		return errors.Wrap(popErr, "Error popping for ExtendedFormatStatusReply")
 	}
diff --git a/plc4go/protocols/cbus/readwrite/model/LevelInformation.go b/plc4go/protocols/cbus/readwrite/model/LevelInformation.go
new file mode 100644
index 000000000..725752b65
--- /dev/null
+++ b/plc4go/protocols/cbus/readwrite/model/LevelInformation.go
@@ -0,0 +1,344 @@
+/*
+ * 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
+ *
+ *   https://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/spi/utils"
+	"github.com/pkg/errors"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// LevelInformation is the corresponding interface of LevelInformation
+type LevelInformation interface {
+	utils.LengthAware
+	utils.Serializable
+	// GetRaw returns Raw (property field)
+	GetRaw() uint16
+	// GetNibble1 returns Nibble1 (virtual field)
+	GetNibble1() uint8
+	// GetNibble2 returns Nibble2 (virtual field)
+	GetNibble2() uint8
+	// GetNibble3 returns Nibble3 (virtual field)
+	GetNibble3() uint8
+	// GetNibble4 returns Nibble4 (virtual field)
+	GetNibble4() uint8
+	// GetIsAbsent returns IsAbsent (virtual field)
+	GetIsAbsent() bool
+	// GetIsCorruptedByNoise returns IsCorruptedByNoise (virtual field)
+	GetIsCorruptedByNoise() bool
+	// GetIsCorruptedByNoiseOrLevelsDiffer returns IsCorruptedByNoiseOrLevelsDiffer (virtual field)
+	GetIsCorruptedByNoiseOrLevelsDiffer() bool
+	// GetIsCorrupted returns IsCorrupted (virtual field)
+	GetIsCorrupted() bool
+}
+
+// LevelInformationExactly can be used when we want exactly this type and not a type which fulfills LevelInformation.
+// This is useful for switch cases.
+type LevelInformationExactly interface {
+	LevelInformation
+	isLevelInformation() bool
+}
+
+// _LevelInformation is the data-structure of this message
+type _LevelInformation struct {
+	_LevelInformationChildRequirements
+	Raw uint16
+}
+
+type _LevelInformationChildRequirements interface {
+	utils.Serializable
+	GetLengthInBits() uint16
+	GetLengthInBitsConditional(lastItem bool) uint16
+}
+
+type LevelInformationParent interface {
+	SerializeParent(writeBuffer utils.WriteBuffer, child LevelInformation, serializeChildFunction func() error) error
+	GetTypeName() string
+}
+
+type LevelInformationChild interface {
+	utils.Serializable
+	InitializeParent(parent LevelInformation, raw uint16)
+	GetParent() *LevelInformation
+
+	GetTypeName() string
+	LevelInformation
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for property fields.
+///////////////////////
+
+func (m *_LevelInformation) GetRaw() uint16 {
+	return m.Raw
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for virtual fields.
+///////////////////////
+
+func (m *_LevelInformation) GetNibble1() uint8 {
+	return uint8(uint8(m.GetRaw()&0xF000) >> uint8(12))
+}
+
+func (m *_LevelInformation) GetNibble2() uint8 {
+	return uint8(uint8(m.GetRaw()&0x0F00) >> uint8(8))
+}
+
+func (m *_LevelInformation) GetNibble3() uint8 {
+	return uint8(uint8(m.GetRaw()&0x00F0) >> uint8(4))
+}
+
+func (m *_LevelInformation) GetNibble4() uint8 {
+	return uint8(uint8(m.GetRaw()&0x000F) >> uint8(0))
+}
+
+func (m *_LevelInformation) GetIsAbsent() bool {
+	return bool(bool(bool(bool(bool((m.GetNibble1()) == (0x0))) && bool(bool((m.GetNibble2()) == (0x0)))) && bool(bool((m.GetNibble3()) == (0x0)))) && bool(bool((m.GetNibble4()) == (0x0))))
+}
+
+func (m *_LevelInformation) GetIsCorruptedByNoise() bool {
+	return bool(bool(!(m.GetIsAbsent())) && bool(bool(bool(bool(bool(bool(bool(bool(bool(bool((m.GetNibble1()) < (0x5)))) || bool(bool(bool((m.GetNibble1()) == (0x8))))) || bool(bool(bool((m.GetNibble1()) == (0xC)))))) || bool(bool(bool(bool(bool(bool((m.GetNibble2()) < (0x5)))) || bool(bool(bool((m.GetNibble2()) == (0x8))))) || bool(bool(bool((m.GetNibble2()) == (0xC))))))) || bool(bool(bool(bool(bool(bool((m.GetNibble3()) < (0x5)))) || bool(bool(bool((m.GetNibble3()) == (0x8))))) || bool( [...]
+}
+
+func (m *_LevelInformation) GetIsCorruptedByNoiseOrLevelsDiffer() bool {
+	return bool(bool(!(m.GetIsAbsent())) && bool(bool(bool(bool(bool(bool(bool(bool(bool(bool((m.GetNibble1()) == (0x7)))) || bool(bool(bool((m.GetNibble1()) == (0xB))))) || bool(bool(bool((m.GetNibble1()) > (0xC)))))) || bool(bool(bool(bool(bool(bool((m.GetNibble2()) == (0x7)))) || bool(bool(bool((m.GetNibble2()) == (0xB))))) || bool(bool(bool((m.GetNibble2()) > (0xC))))))) || bool(bool(bool(bool(bool(bool((m.GetNibble3()) == (0x7)))) || bool(bool(bool((m.GetNibble3()) == (0xB))))) || bool [...]
+}
+
+func (m *_LevelInformation) GetIsCorrupted() bool {
+	return bool(bool(m.GetIsCorruptedByNoise()) || bool(m.GetIsCorruptedByNoiseOrLevelsDiffer()))
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+// NewLevelInformation factory function for _LevelInformation
+func NewLevelInformation(raw uint16) *_LevelInformation {
+	return &_LevelInformation{Raw: raw}
+}
+
+// Deprecated: use the interface for direct cast
+func CastLevelInformation(structType interface{}) LevelInformation {
+	if casted, ok := structType.(LevelInformation); ok {
+		return casted
+	}
+	if casted, ok := structType.(*LevelInformation); ok {
+		return *casted
+	}
+	return nil
+}
+
+func (m *_LevelInformation) GetTypeName() string {
+	return "LevelInformation"
+}
+
+func (m *_LevelInformation) GetParentLengthInBits() uint16 {
+	lengthInBits := uint16(0)
+
+	// A virtual field doesn't have any in- or output.
+
+	// A virtual field doesn't have any in- or output.
+
+	// A virtual field doesn't have any in- or output.
+
+	// A virtual field doesn't have any in- or output.
+
+	// A virtual field doesn't have any in- or output.
+
+	// A virtual field doesn't have any in- or output.
+
+	// A virtual field doesn't have any in- or output.
+
+	// A virtual field doesn't have any in- or output.
+
+	return lengthInBits
+}
+
+func (m *_LevelInformation) GetLengthInBytes() uint16 {
+	return m.GetLengthInBits() / 8
+}
+
+func LevelInformationParse(readBuffer utils.ReadBuffer) (LevelInformation, error) {
+	positionAware := readBuffer
+	_ = positionAware
+	if pullErr := readBuffer.PullContext("LevelInformation"); pullErr != nil {
+		return nil, errors.Wrap(pullErr, "Error pulling for LevelInformation")
+	}
+	currentPos := positionAware.GetPos()
+	_ = currentPos
+
+	// Peek Field (raw)
+	currentPos = positionAware.GetPos()
+	raw, _err := readBuffer.ReadUint16("raw", 16)
+	if _err != nil {
+		return nil, errors.Wrap(_err, "Error parsing 'raw' field of LevelInformation")
+	}
+
+	readBuffer.Reset(currentPos)
+
+	// Virtual field
+	_nibble1 := uint8(raw&0xF000) >> uint8(12)
+	nibble1 := uint8(_nibble1)
+	_ = nibble1
+
+	// Virtual field
+	_nibble2 := uint8(raw&0x0F00) >> uint8(8)
+	nibble2 := uint8(_nibble2)
+	_ = nibble2
+
+	// Virtual field
+	_nibble3 := uint8(raw&0x00F0) >> uint8(4)
+	nibble3 := uint8(_nibble3)
+	_ = nibble3
+
+	// Virtual field
+	_nibble4 := uint8(raw&0x000F) >> uint8(0)
+	nibble4 := uint8(_nibble4)
+	_ = nibble4
+
+	// Virtual field
+	_isAbsent := bool(bool(bool(bool((nibble1) == (0x0))) && bool(bool((nibble2) == (0x0)))) && bool(bool((nibble3) == (0x0)))) && bool(bool((nibble4) == (0x0)))
+	isAbsent := bool(_isAbsent)
+	_ = isAbsent
+
+	// Virtual field
+	_isCorruptedByNoise := bool(!(isAbsent)) && bool(bool(bool(bool(bool(bool(bool(bool(bool(bool((nibble1) < (0x5)))) || bool(bool(bool((nibble1) == (0x8))))) || bool(bool(bool((nibble1) == (0xC)))))) || bool(bool(bool(bool(bool(bool((nibble2) < (0x5)))) || bool(bool(bool((nibble2) == (0x8))))) || bool(bool(bool((nibble2) == (0xC))))))) || bool(bool(bool(bool(bool(bool((nibble3) < (0x5)))) || bool(bool(bool((nibble3) == (0x8))))) || bool(bool(bool((nibble3) == (0xC))))))) || bool(bool(bool [...]
+	isCorruptedByNoise := bool(_isCorruptedByNoise)
+	_ = isCorruptedByNoise
+
+	// Virtual field
+	_isCorruptedByNoiseOrLevelsDiffer := bool(!(isAbsent)) && bool(bool(bool(bool(bool(bool(bool(bool(bool(bool((nibble1) == (0x7)))) || bool(bool(bool((nibble1) == (0xB))))) || bool(bool(bool((nibble1) > (0xC)))))) || bool(bool(bool(bool(bool(bool((nibble2) == (0x7)))) || bool(bool(bool((nibble2) == (0xB))))) || bool(bool(bool((nibble2) > (0xC))))))) || bool(bool(bool(bool(bool(bool((nibble3) == (0x7)))) || bool(bool(bool((nibble3) == (0xB))))) || bool(bool(bool((nibble3) > (0xC))))))) ||  [...]
+	isCorruptedByNoiseOrLevelsDiffer := bool(_isCorruptedByNoiseOrLevelsDiffer)
+	_ = isCorruptedByNoiseOrLevelsDiffer
+
+	// Virtual field
+	_isCorrupted := bool(isCorruptedByNoise) || bool(isCorruptedByNoiseOrLevelsDiffer)
+	isCorrupted := bool(_isCorrupted)
+	_ = isCorrupted
+
+	// Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
+	type LevelInformationChildSerializeRequirement interface {
+		LevelInformation
+		InitializeParent(LevelInformation, uint16)
+		GetParent() LevelInformation
+	}
+	var _childTemp interface{}
+	var _child LevelInformationChildSerializeRequirement
+	var typeSwitchError error
+	switch {
+	case isAbsent == bool(true): // LevelInformationAbsent
+		_childTemp, typeSwitchError = LevelInformationAbsentParse(readBuffer)
+	case 0 == 0 && isCorrupted == bool(true): // LevelInformationCorrupted
+		_childTemp, typeSwitchError = LevelInformationCorruptedParse(readBuffer)
+	case 0 == 0: // LevelInformationNormal
+		_childTemp, typeSwitchError = LevelInformationNormalParse(readBuffer)
+	default:
+		typeSwitchError = errors.Errorf("Unmapped type for parameters [isAbsent=%v, isCorrupted=%v]", isAbsent, isCorrupted)
+	}
+	if typeSwitchError != nil {
+		return nil, errors.Wrap(typeSwitchError, "Error parsing sub-type for type-switch of LevelInformation")
+	}
+	_child = _childTemp.(LevelInformationChildSerializeRequirement)
+
+	if closeErr := readBuffer.CloseContext("LevelInformation"); closeErr != nil {
+		return nil, errors.Wrap(closeErr, "Error closing for LevelInformation")
+	}
+
+	// Finish initializing
+	_child.InitializeParent(_child, raw)
+	return _child, nil
+}
+
+func (pm *_LevelInformation) SerializeParent(writeBuffer utils.WriteBuffer, child LevelInformation, serializeChildFunction func() error) error {
+	// We redirect all calls through client as some methods are only implemented there
+	m := child
+	_ = m
+	positionAware := writeBuffer
+	_ = positionAware
+	if pushErr := writeBuffer.PushContext("LevelInformation"); pushErr != nil {
+		return errors.Wrap(pushErr, "Error pushing for LevelInformation")
+	}
+	// Virtual field
+	if _nibble1Err := writeBuffer.WriteVirtual("nibble1", m.GetNibble1()); _nibble1Err != nil {
+		return errors.Wrap(_nibble1Err, "Error serializing 'nibble1' field")
+	}
+	// Virtual field
+	if _nibble2Err := writeBuffer.WriteVirtual("nibble2", m.GetNibble2()); _nibble2Err != nil {
+		return errors.Wrap(_nibble2Err, "Error serializing 'nibble2' field")
+	}
+	// Virtual field
+	if _nibble3Err := writeBuffer.WriteVirtual("nibble3", m.GetNibble3()); _nibble3Err != nil {
+		return errors.Wrap(_nibble3Err, "Error serializing 'nibble3' field")
+	}
+	// Virtual field
+	if _nibble4Err := writeBuffer.WriteVirtual("nibble4", m.GetNibble4()); _nibble4Err != nil {
+		return errors.Wrap(_nibble4Err, "Error serializing 'nibble4' field")
+	}
+	// Virtual field
+	if _isAbsentErr := writeBuffer.WriteVirtual("isAbsent", m.GetIsAbsent()); _isAbsentErr != nil {
+		return errors.Wrap(_isAbsentErr, "Error serializing 'isAbsent' field")
+	}
+	// Virtual field
+	if _isCorruptedByNoiseErr := writeBuffer.WriteVirtual("isCorruptedByNoise", m.GetIsCorruptedByNoise()); _isCorruptedByNoiseErr != nil {
+		return errors.Wrap(_isCorruptedByNoiseErr, "Error serializing 'isCorruptedByNoise' field")
+	}
+	// Virtual field
+	if _isCorruptedByNoiseOrLevelsDifferErr := writeBuffer.WriteVirtual("isCorruptedByNoiseOrLevelsDiffer", m.GetIsCorruptedByNoiseOrLevelsDiffer()); _isCorruptedByNoiseOrLevelsDifferErr != nil {
+		return errors.Wrap(_isCorruptedByNoiseOrLevelsDifferErr, "Error serializing 'isCorruptedByNoiseOrLevelsDiffer' field")
+	}
+	// Virtual field
+	if _isCorruptedErr := writeBuffer.WriteVirtual("isCorrupted", m.GetIsCorrupted()); _isCorruptedErr != nil {
+		return errors.Wrap(_isCorruptedErr, "Error serializing 'isCorrupted' field")
+	}
+
+	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
+		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
+	}
+
+	if popErr := writeBuffer.PopContext("LevelInformation"); popErr != nil {
+		return errors.Wrap(popErr, "Error popping for LevelInformation")
+	}
+	return nil
+}
+
+func (m *_LevelInformation) isLevelInformation() bool {
+	return true
+}
+
+func (m *_LevelInformation) String() string {
+	if m == nil {
+		return "<nil>"
+	}
+	writeBuffer := utils.NewBoxedWriteBufferWithOptions(true, true)
+	if err := writeBuffer.WriteSerializable(m); err != nil {
+		return err.Error()
+	}
+	return writeBuffer.GetBox().String()
+}
diff --git a/plc4go/protocols/cbus/readwrite/model/LevelInformationAbsent.go b/plc4go/protocols/cbus/readwrite/model/LevelInformationAbsent.go
new file mode 100644
index 000000000..21f605429
--- /dev/null
+++ b/plc4go/protocols/cbus/readwrite/model/LevelInformationAbsent.go
@@ -0,0 +1,180 @@
+/*
+ * 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
+ *
+ *   https://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/spi/utils"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// LevelInformationAbsent is the corresponding interface of LevelInformationAbsent
+type LevelInformationAbsent interface {
+	utils.LengthAware
+	utils.Serializable
+	LevelInformation
+}
+
+// LevelInformationAbsentExactly can be used when we want exactly this type and not a type which fulfills LevelInformationAbsent.
+// This is useful for switch cases.
+type LevelInformationAbsentExactly interface {
+	LevelInformationAbsent
+	isLevelInformationAbsent() bool
+}
+
+// _LevelInformationAbsent is the data-structure of this message
+type _LevelInformationAbsent struct {
+	*_LevelInformation
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for discriminator values.
+///////////////////////
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+func (m *_LevelInformationAbsent) InitializeParent(parent LevelInformation, raw uint16) {
+	m.Raw = raw
+}
+
+func (m *_LevelInformationAbsent) GetParent() LevelInformation {
+	return m._LevelInformation
+}
+
+// NewLevelInformationAbsent factory function for _LevelInformationAbsent
+func NewLevelInformationAbsent(raw uint16) *_LevelInformationAbsent {
+	_result := &_LevelInformationAbsent{
+		_LevelInformation: NewLevelInformation(raw),
+	}
+	_result._LevelInformation._LevelInformationChildRequirements = _result
+	return _result
+}
+
+// Deprecated: use the interface for direct cast
+func CastLevelInformationAbsent(structType interface{}) LevelInformationAbsent {
+	if casted, ok := structType.(LevelInformationAbsent); ok {
+		return casted
+	}
+	if casted, ok := structType.(*LevelInformationAbsent); ok {
+		return *casted
+	}
+	return nil
+}
+
+func (m *_LevelInformationAbsent) GetTypeName() string {
+	return "LevelInformationAbsent"
+}
+
+func (m *_LevelInformationAbsent) GetLengthInBits() uint16 {
+	return m.GetLengthInBitsConditional(false)
+}
+
+func (m *_LevelInformationAbsent) GetLengthInBitsConditional(lastItem bool) uint16 {
+	lengthInBits := uint16(m.GetParentLengthInBits())
+
+	// Reserved Field (reserved)
+	lengthInBits += 16
+
+	return lengthInBits
+}
+
+func (m *_LevelInformationAbsent) GetLengthInBytes() uint16 {
+	return m.GetLengthInBits() / 8
+}
+
+func LevelInformationAbsentParse(readBuffer utils.ReadBuffer) (LevelInformationAbsent, error) {
+	positionAware := readBuffer
+	_ = positionAware
+	if pullErr := readBuffer.PullContext("LevelInformationAbsent"); pullErr != nil {
+		return nil, errors.Wrap(pullErr, "Error pulling for LevelInformationAbsent")
+	}
+	currentPos := positionAware.GetPos()
+	_ = currentPos
+
+	// Reserved Field (Compartmentalized so the "reserved" variable can't leak)
+	{
+		reserved, _err := readBuffer.ReadUint16("reserved", 16)
+		if _err != nil {
+			return nil, errors.Wrap(_err, "Error parsing 'reserved' field of LevelInformationAbsent")
+		}
+		if reserved != uint16(0x0000) {
+			log.Info().Fields(map[string]interface{}{
+				"expected value": uint16(0x0000),
+				"got value":      reserved,
+			}).Msg("Got unexpected response for reserved field.")
+		}
+	}
+
+	if closeErr := readBuffer.CloseContext("LevelInformationAbsent"); closeErr != nil {
+		return nil, errors.Wrap(closeErr, "Error closing for LevelInformationAbsent")
+	}
+
+	// Create a partially initialized instance
+	_child := &_LevelInformationAbsent{
+		_LevelInformation: &_LevelInformation{},
+	}
+	_child._LevelInformation._LevelInformationChildRequirements = _child
+	return _child, nil
+}
+
+func (m *_LevelInformationAbsent) Serialize(writeBuffer utils.WriteBuffer) error {
+	positionAware := writeBuffer
+	_ = positionAware
+	ser := func() error {
+		if pushErr := writeBuffer.PushContext("LevelInformationAbsent"); pushErr != nil {
+			return errors.Wrap(pushErr, "Error pushing for LevelInformationAbsent")
+		}
+
+		// Reserved Field (reserved)
+		{
+			_err := writeBuffer.WriteUint16("reserved", 16, uint16(0x0000))
+			if _err != nil {
+				return errors.Wrap(_err, "Error serializing 'reserved' field")
+			}
+		}
+
+		if popErr := writeBuffer.PopContext("LevelInformationAbsent"); popErr != nil {
+			return errors.Wrap(popErr, "Error popping for LevelInformationAbsent")
+		}
+		return nil
+	}
+	return m.SerializeParent(writeBuffer, m, ser)
+}
+
+func (m *_LevelInformationAbsent) isLevelInformationAbsent() bool {
+	return true
+}
+
+func (m *_LevelInformationAbsent) String() string {
+	if m == nil {
+		return "<nil>"
+	}
+	writeBuffer := utils.NewBoxedWriteBufferWithOptions(true, true)
+	if err := writeBuffer.WriteSerializable(m); err != nil {
+		return err.Error()
+	}
+	return writeBuffer.GetBox().String()
+}
diff --git a/plc4go/protocols/cbus/readwrite/model/LevelInformationCorrupted.go b/plc4go/protocols/cbus/readwrite/model/LevelInformationCorrupted.go
new file mode 100644
index 000000000..032c02237
--- /dev/null
+++ b/plc4go/protocols/cbus/readwrite/model/LevelInformationCorrupted.go
@@ -0,0 +1,268 @@
+/*
+ * 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
+ *
+ *   https://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/spi/utils"
+	"github.com/pkg/errors"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// LevelInformationCorrupted is the corresponding interface of LevelInformationCorrupted
+type LevelInformationCorrupted interface {
+	utils.LengthAware
+	utils.Serializable
+	LevelInformation
+	// GetCorruptedNibble1 returns CorruptedNibble1 (property field)
+	GetCorruptedNibble1() uint8
+	// GetCorruptedNibble2 returns CorruptedNibble2 (property field)
+	GetCorruptedNibble2() uint8
+	// GetCorruptedNibble3 returns CorruptedNibble3 (property field)
+	GetCorruptedNibble3() uint8
+	// GetCorruptedNibble4 returns CorruptedNibble4 (property field)
+	GetCorruptedNibble4() uint8
+}
+
+// LevelInformationCorruptedExactly can be used when we want exactly this type and not a type which fulfills LevelInformationCorrupted.
+// This is useful for switch cases.
+type LevelInformationCorruptedExactly interface {
+	LevelInformationCorrupted
+	isLevelInformationCorrupted() bool
+}
+
+// _LevelInformationCorrupted is the data-structure of this message
+type _LevelInformationCorrupted struct {
+	*_LevelInformation
+	CorruptedNibble1 uint8
+	CorruptedNibble2 uint8
+	CorruptedNibble3 uint8
+	CorruptedNibble4 uint8
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for discriminator values.
+///////////////////////
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+func (m *_LevelInformationCorrupted) InitializeParent(parent LevelInformation, raw uint16) {
+	m.Raw = raw
+}
+
+func (m *_LevelInformationCorrupted) GetParent() LevelInformation {
+	return m._LevelInformation
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for property fields.
+///////////////////////
+
+func (m *_LevelInformationCorrupted) GetCorruptedNibble1() uint8 {
+	return m.CorruptedNibble1
+}
+
+func (m *_LevelInformationCorrupted) GetCorruptedNibble2() uint8 {
+	return m.CorruptedNibble2
+}
+
+func (m *_LevelInformationCorrupted) GetCorruptedNibble3() uint8 {
+	return m.CorruptedNibble3
+}
+
+func (m *_LevelInformationCorrupted) GetCorruptedNibble4() uint8 {
+	return m.CorruptedNibble4
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+// NewLevelInformationCorrupted factory function for _LevelInformationCorrupted
+func NewLevelInformationCorrupted(corruptedNibble1 uint8, corruptedNibble2 uint8, corruptedNibble3 uint8, corruptedNibble4 uint8, raw uint16) *_LevelInformationCorrupted {
+	_result := &_LevelInformationCorrupted{
+		CorruptedNibble1:  corruptedNibble1,
+		CorruptedNibble2:  corruptedNibble2,
+		CorruptedNibble3:  corruptedNibble3,
+		CorruptedNibble4:  corruptedNibble4,
+		_LevelInformation: NewLevelInformation(raw),
+	}
+	_result._LevelInformation._LevelInformationChildRequirements = _result
+	return _result
+}
+
+// Deprecated: use the interface for direct cast
+func CastLevelInformationCorrupted(structType interface{}) LevelInformationCorrupted {
+	if casted, ok := structType.(LevelInformationCorrupted); ok {
+		return casted
+	}
+	if casted, ok := structType.(*LevelInformationCorrupted); ok {
+		return *casted
+	}
+	return nil
+}
+
+func (m *_LevelInformationCorrupted) GetTypeName() string {
+	return "LevelInformationCorrupted"
+}
+
+func (m *_LevelInformationCorrupted) GetLengthInBits() uint16 {
+	return m.GetLengthInBitsConditional(false)
+}
+
+func (m *_LevelInformationCorrupted) GetLengthInBitsConditional(lastItem bool) uint16 {
+	lengthInBits := uint16(m.GetParentLengthInBits())
+
+	// Simple field (corruptedNibble1)
+	lengthInBits += 4
+
+	// Simple field (corruptedNibble2)
+	lengthInBits += 4
+
+	// Simple field (corruptedNibble3)
+	lengthInBits += 4
+
+	// Simple field (corruptedNibble4)
+	lengthInBits += 4
+
+	return lengthInBits
+}
+
+func (m *_LevelInformationCorrupted) GetLengthInBytes() uint16 {
+	return m.GetLengthInBits() / 8
+}
+
+func LevelInformationCorruptedParse(readBuffer utils.ReadBuffer) (LevelInformationCorrupted, error) {
+	positionAware := readBuffer
+	_ = positionAware
+	if pullErr := readBuffer.PullContext("LevelInformationCorrupted"); pullErr != nil {
+		return nil, errors.Wrap(pullErr, "Error pulling for LevelInformationCorrupted")
+	}
+	currentPos := positionAware.GetPos()
+	_ = currentPos
+
+	// Simple Field (corruptedNibble1)
+	_corruptedNibble1, _corruptedNibble1Err := readBuffer.ReadUint8("corruptedNibble1", 4)
+	if _corruptedNibble1Err != nil {
+		return nil, errors.Wrap(_corruptedNibble1Err, "Error parsing 'corruptedNibble1' field of LevelInformationCorrupted")
+	}
+	corruptedNibble1 := _corruptedNibble1
+
+	// Simple Field (corruptedNibble2)
+	_corruptedNibble2, _corruptedNibble2Err := readBuffer.ReadUint8("corruptedNibble2", 4)
+	if _corruptedNibble2Err != nil {
+		return nil, errors.Wrap(_corruptedNibble2Err, "Error parsing 'corruptedNibble2' field of LevelInformationCorrupted")
+	}
+	corruptedNibble2 := _corruptedNibble2
+
+	// Simple Field (corruptedNibble3)
+	_corruptedNibble3, _corruptedNibble3Err := readBuffer.ReadUint8("corruptedNibble3", 4)
+	if _corruptedNibble3Err != nil {
+		return nil, errors.Wrap(_corruptedNibble3Err, "Error parsing 'corruptedNibble3' field of LevelInformationCorrupted")
+	}
+	corruptedNibble3 := _corruptedNibble3
+
+	// Simple Field (corruptedNibble4)
+	_corruptedNibble4, _corruptedNibble4Err := readBuffer.ReadUint8("corruptedNibble4", 4)
+	if _corruptedNibble4Err != nil {
+		return nil, errors.Wrap(_corruptedNibble4Err, "Error parsing 'corruptedNibble4' field of LevelInformationCorrupted")
+	}
+	corruptedNibble4 := _corruptedNibble4
+
+	if closeErr := readBuffer.CloseContext("LevelInformationCorrupted"); closeErr != nil {
+		return nil, errors.Wrap(closeErr, "Error closing for LevelInformationCorrupted")
+	}
+
+	// Create a partially initialized instance
+	_child := &_LevelInformationCorrupted{
+		CorruptedNibble1:  corruptedNibble1,
+		CorruptedNibble2:  corruptedNibble2,
+		CorruptedNibble3:  corruptedNibble3,
+		CorruptedNibble4:  corruptedNibble4,
+		_LevelInformation: &_LevelInformation{},
+	}
+	_child._LevelInformation._LevelInformationChildRequirements = _child
+	return _child, nil
+}
+
+func (m *_LevelInformationCorrupted) Serialize(writeBuffer utils.WriteBuffer) error {
+	positionAware := writeBuffer
+	_ = positionAware
+	ser := func() error {
+		if pushErr := writeBuffer.PushContext("LevelInformationCorrupted"); pushErr != nil {
+			return errors.Wrap(pushErr, "Error pushing for LevelInformationCorrupted")
+		}
+
+		// Simple Field (corruptedNibble1)
+		corruptedNibble1 := uint8(m.GetCorruptedNibble1())
+		_corruptedNibble1Err := writeBuffer.WriteUint8("corruptedNibble1", 4, (corruptedNibble1))
+		if _corruptedNibble1Err != nil {
+			return errors.Wrap(_corruptedNibble1Err, "Error serializing 'corruptedNibble1' field")
+		}
+
+		// Simple Field (corruptedNibble2)
+		corruptedNibble2 := uint8(m.GetCorruptedNibble2())
+		_corruptedNibble2Err := writeBuffer.WriteUint8("corruptedNibble2", 4, (corruptedNibble2))
+		if _corruptedNibble2Err != nil {
+			return errors.Wrap(_corruptedNibble2Err, "Error serializing 'corruptedNibble2' field")
+		}
+
+		// Simple Field (corruptedNibble3)
+		corruptedNibble3 := uint8(m.GetCorruptedNibble3())
+		_corruptedNibble3Err := writeBuffer.WriteUint8("corruptedNibble3", 4, (corruptedNibble3))
+		if _corruptedNibble3Err != nil {
+			return errors.Wrap(_corruptedNibble3Err, "Error serializing 'corruptedNibble3' field")
+		}
+
+		// Simple Field (corruptedNibble4)
+		corruptedNibble4 := uint8(m.GetCorruptedNibble4())
+		_corruptedNibble4Err := writeBuffer.WriteUint8("corruptedNibble4", 4, (corruptedNibble4))
+		if _corruptedNibble4Err != nil {
+			return errors.Wrap(_corruptedNibble4Err, "Error serializing 'corruptedNibble4' field")
+		}
+
+		if popErr := writeBuffer.PopContext("LevelInformationCorrupted"); popErr != nil {
+			return errors.Wrap(popErr, "Error popping for LevelInformationCorrupted")
+		}
+		return nil
+	}
+	return m.SerializeParent(writeBuffer, m, ser)
+}
+
+func (m *_LevelInformationCorrupted) isLevelInformationCorrupted() bool {
+	return true
+}
+
+func (m *_LevelInformationCorrupted) String() string {
+	if m == nil {
+		return "<nil>"
+	}
+	writeBuffer := utils.NewBoxedWriteBufferWithOptions(true, true)
+	if err := writeBuffer.WriteSerializable(m); err != nil {
+		return err.Error()
+	}
+	return writeBuffer.GetBox().String()
+}
diff --git a/plc4go/protocols/cbus/readwrite/model/LevelInformationNibblePair.go b/plc4go/protocols/cbus/readwrite/model/LevelInformationNibblePair.go
new file mode 100644
index 000000000..c922ac549
--- /dev/null
+++ b/plc4go/protocols/cbus/readwrite/model/LevelInformationNibblePair.go
@@ -0,0 +1,323 @@
+/*
+ * 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
+ *
+ *   https://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/spi/utils"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// LevelInformationNibblePair is an enum
+type LevelInformationNibblePair uint8
+
+type ILevelInformationNibblePair interface {
+	NibbleValue() uint8
+	Serialize(writeBuffer utils.WriteBuffer) error
+}
+
+const (
+	LevelInformationNibblePair_Value_F LevelInformationNibblePair = 0x55
+	LevelInformationNibblePair_Value_E LevelInformationNibblePair = 0x56
+	LevelInformationNibblePair_Value_D LevelInformationNibblePair = 0x59
+	LevelInformationNibblePair_Value_C LevelInformationNibblePair = 0x5A
+	LevelInformationNibblePair_Value_B LevelInformationNibblePair = 0x65
+	LevelInformationNibblePair_Value_A LevelInformationNibblePair = 0x66
+	LevelInformationNibblePair_Value_9 LevelInformationNibblePair = 0x69
+	LevelInformationNibblePair_Value_8 LevelInformationNibblePair = 0x6A
+	LevelInformationNibblePair_Value_7 LevelInformationNibblePair = 0x95
+	LevelInformationNibblePair_Value_6 LevelInformationNibblePair = 0x96
+	LevelInformationNibblePair_Value_5 LevelInformationNibblePair = 0x99
+	LevelInformationNibblePair_Value_4 LevelInformationNibblePair = 0x9A
+	LevelInformationNibblePair_Value_3 LevelInformationNibblePair = 0xA5
+	LevelInformationNibblePair_Value_2 LevelInformationNibblePair = 0xA6
+	LevelInformationNibblePair_Value_1 LevelInformationNibblePair = 0xA9
+	LevelInformationNibblePair_Value_0 LevelInformationNibblePair = 0xAA
+)
+
+var LevelInformationNibblePairValues []LevelInformationNibblePair
+
+func init() {
+	_ = errors.New
+	LevelInformationNibblePairValues = []LevelInformationNibblePair{
+		LevelInformationNibblePair_Value_F,
+		LevelInformationNibblePair_Value_E,
+		LevelInformationNibblePair_Value_D,
+		LevelInformationNibblePair_Value_C,
+		LevelInformationNibblePair_Value_B,
+		LevelInformationNibblePair_Value_A,
+		LevelInformationNibblePair_Value_9,
+		LevelInformationNibblePair_Value_8,
+		LevelInformationNibblePair_Value_7,
+		LevelInformationNibblePair_Value_6,
+		LevelInformationNibblePair_Value_5,
+		LevelInformationNibblePair_Value_4,
+		LevelInformationNibblePair_Value_3,
+		LevelInformationNibblePair_Value_2,
+		LevelInformationNibblePair_Value_1,
+		LevelInformationNibblePair_Value_0,
+	}
+}
+
+func (e LevelInformationNibblePair) NibbleValue() uint8 {
+	switch e {
+	case 0x55:
+		{ /* '0x55' */
+			return 0xF
+		}
+	case 0x56:
+		{ /* '0x56' */
+			return 0xE
+		}
+	case 0x59:
+		{ /* '0x59' */
+			return 0xD
+		}
+	case 0x5A:
+		{ /* '0x5A' */
+			return 0xC
+		}
+	case 0x65:
+		{ /* '0x65' */
+			return 0xB
+		}
+	case 0x66:
+		{ /* '0x66' */
+			return 0xA
+		}
+	case 0x69:
+		{ /* '0x69' */
+			return 0x9
+		}
+	case 0x6A:
+		{ /* '0x6A' */
+			return 0x8
+		}
+	case 0x95:
+		{ /* '0x95' */
+			return 0x7
+		}
+	case 0x96:
+		{ /* '0x96' */
+			return 0x6
+		}
+	case 0x99:
+		{ /* '0x99' */
+			return 0x5
+		}
+	case 0x9A:
+		{ /* '0x9A' */
+			return 0x4
+		}
+	case 0xA5:
+		{ /* '0xA5' */
+			return 0x3
+		}
+	case 0xA6:
+		{ /* '0xA6' */
+			return 0x2
+		}
+	case 0xA9:
+		{ /* '0xA9' */
+			return 0x1
+		}
+	case 0xAA:
+		{ /* '0xAA' */
+			return 0x0
+		}
+	default:
+		{
+			return 0
+		}
+	}
+}
+
+func LevelInformationNibblePairFirstEnumForFieldNibbleValue(value uint8) (LevelInformationNibblePair, error) {
+	for _, sizeValue := range LevelInformationNibblePairValues {
+		if sizeValue.NibbleValue() == value {
+			return sizeValue, nil
+		}
+	}
+	return 0, errors.Errorf("enum for %v describing NibbleValue not found", value)
+}
+func LevelInformationNibblePairByValue(value uint8) (enum LevelInformationNibblePair, ok bool) {
+	switch value {
+	case 0x55:
+		return LevelInformationNibblePair_Value_F, true
+	case 0x56:
+		return LevelInformationNibblePair_Value_E, true
+	case 0x59:
+		return LevelInformationNibblePair_Value_D, true
+	case 0x5A:
+		return LevelInformationNibblePair_Value_C, true
+	case 0x65:
+		return LevelInformationNibblePair_Value_B, true
+	case 0x66:
+		return LevelInformationNibblePair_Value_A, true
+	case 0x69:
+		return LevelInformationNibblePair_Value_9, true
+	case 0x6A:
+		return LevelInformationNibblePair_Value_8, true
+	case 0x95:
+		return LevelInformationNibblePair_Value_7, true
+	case 0x96:
+		return LevelInformationNibblePair_Value_6, true
+	case 0x99:
+		return LevelInformationNibblePair_Value_5, true
+	case 0x9A:
+		return LevelInformationNibblePair_Value_4, true
+	case 0xA5:
+		return LevelInformationNibblePair_Value_3, true
+	case 0xA6:
+		return LevelInformationNibblePair_Value_2, true
+	case 0xA9:
+		return LevelInformationNibblePair_Value_1, true
+	case 0xAA:
+		return LevelInformationNibblePair_Value_0, true
+	}
+	return 0, false
+}
+
+func LevelInformationNibblePairByName(value string) (enum LevelInformationNibblePair, ok bool) {
+	switch value {
+	case "Value_F":
+		return LevelInformationNibblePair_Value_F, true
+	case "Value_E":
+		return LevelInformationNibblePair_Value_E, true
+	case "Value_D":
+		return LevelInformationNibblePair_Value_D, true
+	case "Value_C":
+		return LevelInformationNibblePair_Value_C, true
+	case "Value_B":
+		return LevelInformationNibblePair_Value_B, true
+	case "Value_A":
+		return LevelInformationNibblePair_Value_A, true
+	case "Value_9":
+		return LevelInformationNibblePair_Value_9, true
+	case "Value_8":
+		return LevelInformationNibblePair_Value_8, true
+	case "Value_7":
+		return LevelInformationNibblePair_Value_7, true
+	case "Value_6":
+		return LevelInformationNibblePair_Value_6, true
+	case "Value_5":
+		return LevelInformationNibblePair_Value_5, true
+	case "Value_4":
+		return LevelInformationNibblePair_Value_4, true
+	case "Value_3":
+		return LevelInformationNibblePair_Value_3, true
+	case "Value_2":
+		return LevelInformationNibblePair_Value_2, true
+	case "Value_1":
+		return LevelInformationNibblePair_Value_1, true
+	case "Value_0":
+		return LevelInformationNibblePair_Value_0, true
+	}
+	return 0, false
+}
+
+func LevelInformationNibblePairKnows(value uint8) bool {
+	for _, typeValue := range LevelInformationNibblePairValues {
+		if uint8(typeValue) == value {
+			return true
+		}
+	}
+	return false
+}
+
+func CastLevelInformationNibblePair(structType interface{}) LevelInformationNibblePair {
+	castFunc := func(typ interface{}) LevelInformationNibblePair {
+		if sLevelInformationNibblePair, ok := typ.(LevelInformationNibblePair); ok {
+			return sLevelInformationNibblePair
+		}
+		return 0
+	}
+	return castFunc(structType)
+}
+
+func (m LevelInformationNibblePair) GetLengthInBits() uint16 {
+	return 8
+}
+
+func (m LevelInformationNibblePair) GetLengthInBytes() uint16 {
+	return m.GetLengthInBits() / 8
+}
+
+func LevelInformationNibblePairParse(readBuffer utils.ReadBuffer) (LevelInformationNibblePair, error) {
+	val, err := readBuffer.ReadUint8("LevelInformationNibblePair", 8)
+	if err != nil {
+		return 0, errors.Wrap(err, "error reading LevelInformationNibblePair")
+	}
+	if enum, ok := LevelInformationNibblePairByValue(val); !ok {
+		log.Debug().Msgf("no value %x found for RequestType", val)
+		return LevelInformationNibblePair(val), nil
+	} else {
+		return enum, nil
+	}
+}
+
+func (e LevelInformationNibblePair) Serialize(writeBuffer utils.WriteBuffer) error {
+	return writeBuffer.WriteUint8("LevelInformationNibblePair", 8, uint8(e), utils.WithAdditionalStringRepresentation(e.PLC4XEnumName()))
+}
+
+// PLC4XEnumName returns the name that is used in code to identify this enum
+func (e LevelInformationNibblePair) PLC4XEnumName() string {
+	switch e {
+	case LevelInformationNibblePair_Value_F:
+		return "Value_F"
+	case LevelInformationNibblePair_Value_E:
+		return "Value_E"
+	case LevelInformationNibblePair_Value_D:
+		return "Value_D"
+	case LevelInformationNibblePair_Value_C:
+		return "Value_C"
+	case LevelInformationNibblePair_Value_B:
+		return "Value_B"
+	case LevelInformationNibblePair_Value_A:
+		return "Value_A"
+	case LevelInformationNibblePair_Value_9:
+		return "Value_9"
+	case LevelInformationNibblePair_Value_8:
+		return "Value_8"
+	case LevelInformationNibblePair_Value_7:
+		return "Value_7"
+	case LevelInformationNibblePair_Value_6:
+		return "Value_6"
+	case LevelInformationNibblePair_Value_5:
+		return "Value_5"
+	case LevelInformationNibblePair_Value_4:
+		return "Value_4"
+	case LevelInformationNibblePair_Value_3:
+		return "Value_3"
+	case LevelInformationNibblePair_Value_2:
+		return "Value_2"
+	case LevelInformationNibblePair_Value_1:
+		return "Value_1"
+	case LevelInformationNibblePair_Value_0:
+		return "Value_0"
+	}
+	return ""
+}
+
+func (e LevelInformationNibblePair) String() string {
+	return e.PLC4XEnumName()
+}
diff --git a/plc4go/protocols/cbus/readwrite/model/LevelInformationNormal.go b/plc4go/protocols/cbus/readwrite/model/LevelInformationNormal.go
new file mode 100644
index 000000000..491f8abdb
--- /dev/null
+++ b/plc4go/protocols/cbus/readwrite/model/LevelInformationNormal.go
@@ -0,0 +1,264 @@
+/*
+ * 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
+ *
+ *   https://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/spi/utils"
+	"github.com/pkg/errors"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// LevelInformationNormal is the corresponding interface of LevelInformationNormal
+type LevelInformationNormal interface {
+	utils.LengthAware
+	utils.Serializable
+	LevelInformation
+	// GetPair1 returns Pair1 (property field)
+	GetPair1() LevelInformationNibblePair
+	// GetPair2 returns Pair2 (property field)
+	GetPair2() LevelInformationNibblePair
+	// GetActualLevel returns ActualLevel (virtual field)
+	GetActualLevel() uint8
+}
+
+// LevelInformationNormalExactly can be used when we want exactly this type and not a type which fulfills LevelInformationNormal.
+// This is useful for switch cases.
+type LevelInformationNormalExactly interface {
+	LevelInformationNormal
+	isLevelInformationNormal() bool
+}
+
+// _LevelInformationNormal is the data-structure of this message
+type _LevelInformationNormal struct {
+	*_LevelInformation
+	Pair1 LevelInformationNibblePair
+	Pair2 LevelInformationNibblePair
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for discriminator values.
+///////////////////////
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+func (m *_LevelInformationNormal) InitializeParent(parent LevelInformation, raw uint16) {
+	m.Raw = raw
+}
+
+func (m *_LevelInformationNormal) GetParent() LevelInformation {
+	return m._LevelInformation
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for property fields.
+///////////////////////
+
+func (m *_LevelInformationNormal) GetPair1() LevelInformationNibblePair {
+	return m.Pair1
+}
+
+func (m *_LevelInformationNormal) GetPair2() LevelInformationNibblePair {
+	return m.Pair2
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for virtual fields.
+///////////////////////
+
+func (m *_LevelInformationNormal) GetActualLevel() uint8 {
+	return uint8(m.GetPair2().NibbleValue()<<uint8(4) | m.GetPair1().NibbleValue())
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+// NewLevelInformationNormal factory function for _LevelInformationNormal
+func NewLevelInformationNormal(pair1 LevelInformationNibblePair, pair2 LevelInformationNibblePair, raw uint16) *_LevelInformationNormal {
+	_result := &_LevelInformationNormal{
+		Pair1:             pair1,
+		Pair2:             pair2,
+		_LevelInformation: NewLevelInformation(raw),
+	}
+	_result._LevelInformation._LevelInformationChildRequirements = _result
+	return _result
+}
+
+// Deprecated: use the interface for direct cast
+func CastLevelInformationNormal(structType interface{}) LevelInformationNormal {
+	if casted, ok := structType.(LevelInformationNormal); ok {
+		return casted
+	}
+	if casted, ok := structType.(*LevelInformationNormal); ok {
+		return *casted
+	}
+	return nil
+}
+
+func (m *_LevelInformationNormal) GetTypeName() string {
+	return "LevelInformationNormal"
+}
+
+func (m *_LevelInformationNormal) GetLengthInBits() uint16 {
+	return m.GetLengthInBitsConditional(false)
+}
+
+func (m *_LevelInformationNormal) GetLengthInBitsConditional(lastItem bool) uint16 {
+	lengthInBits := uint16(m.GetParentLengthInBits())
+
+	// Simple field (pair1)
+	lengthInBits += 8
+
+	// Simple field (pair2)
+	lengthInBits += 8
+
+	// A virtual field doesn't have any in- or output.
+
+	return lengthInBits
+}
+
+func (m *_LevelInformationNormal) GetLengthInBytes() uint16 {
+	return m.GetLengthInBits() / 8
+}
+
+func LevelInformationNormalParse(readBuffer utils.ReadBuffer) (LevelInformationNormal, error) {
+	positionAware := readBuffer
+	_ = positionAware
+	if pullErr := readBuffer.PullContext("LevelInformationNormal"); pullErr != nil {
+		return nil, errors.Wrap(pullErr, "Error pulling for LevelInformationNormal")
+	}
+	currentPos := positionAware.GetPos()
+	_ = currentPos
+
+	// Simple Field (pair1)
+	if pullErr := readBuffer.PullContext("pair1"); pullErr != nil {
+		return nil, errors.Wrap(pullErr, "Error pulling for pair1")
+	}
+	_pair1, _pair1Err := LevelInformationNibblePairParse(readBuffer)
+	if _pair1Err != nil {
+		return nil, errors.Wrap(_pair1Err, "Error parsing 'pair1' field of LevelInformationNormal")
+	}
+	pair1 := _pair1
+	if closeErr := readBuffer.CloseContext("pair1"); closeErr != nil {
+		return nil, errors.Wrap(closeErr, "Error closing for pair1")
+	}
+
+	// Simple Field (pair2)
+	if pullErr := readBuffer.PullContext("pair2"); pullErr != nil {
+		return nil, errors.Wrap(pullErr, "Error pulling for pair2")
+	}
+	_pair2, _pair2Err := LevelInformationNibblePairParse(readBuffer)
+	if _pair2Err != nil {
+		return nil, errors.Wrap(_pair2Err, "Error parsing 'pair2' field of LevelInformationNormal")
+	}
+	pair2 := _pair2
+	if closeErr := readBuffer.CloseContext("pair2"); closeErr != nil {
+		return nil, errors.Wrap(closeErr, "Error closing for pair2")
+	}
+
+	// Virtual field
+	_actualLevel := pair2.NibbleValue()<<uint8(4) | pair1.NibbleValue()
+	actualLevel := uint8(_actualLevel)
+	_ = actualLevel
+
+	if closeErr := readBuffer.CloseContext("LevelInformationNormal"); closeErr != nil {
+		return nil, errors.Wrap(closeErr, "Error closing for LevelInformationNormal")
+	}
+
+	// Create a partially initialized instance
+	_child := &_LevelInformationNormal{
+		Pair1:             pair1,
+		Pair2:             pair2,
+		_LevelInformation: &_LevelInformation{},
+	}
+	_child._LevelInformation._LevelInformationChildRequirements = _child
+	return _child, nil
+}
+
+func (m *_LevelInformationNormal) Serialize(writeBuffer utils.WriteBuffer) error {
+	positionAware := writeBuffer
+	_ = positionAware
+	ser := func() error {
+		if pushErr := writeBuffer.PushContext("LevelInformationNormal"); pushErr != nil {
+			return errors.Wrap(pushErr, "Error pushing for LevelInformationNormal")
+		}
+
+		// Simple Field (pair1)
+		if pushErr := writeBuffer.PushContext("pair1"); pushErr != nil {
+			return errors.Wrap(pushErr, "Error pushing for pair1")
+		}
+		_pair1Err := writeBuffer.WriteSerializable(m.GetPair1())
+		if popErr := writeBuffer.PopContext("pair1"); popErr != nil {
+			return errors.Wrap(popErr, "Error popping for pair1")
+		}
+		if _pair1Err != nil {
+			return errors.Wrap(_pair1Err, "Error serializing 'pair1' field")
+		}
+
+		// Simple Field (pair2)
+		if pushErr := writeBuffer.PushContext("pair2"); pushErr != nil {
+			return errors.Wrap(pushErr, "Error pushing for pair2")
+		}
+		_pair2Err := writeBuffer.WriteSerializable(m.GetPair2())
+		if popErr := writeBuffer.PopContext("pair2"); popErr != nil {
+			return errors.Wrap(popErr, "Error popping for pair2")
+		}
+		if _pair2Err != nil {
+			return errors.Wrap(_pair2Err, "Error serializing 'pair2' field")
+		}
+		// Virtual field
+		if _actualLevelErr := writeBuffer.WriteVirtual("actualLevel", m.GetActualLevel()); _actualLevelErr != nil {
+			return errors.Wrap(_actualLevelErr, "Error serializing 'actualLevel' field")
+		}
+
+		if popErr := writeBuffer.PopContext("LevelInformationNormal"); popErr != nil {
+			return errors.Wrap(popErr, "Error popping for LevelInformationNormal")
+		}
+		return nil
+	}
+	return m.SerializeParent(writeBuffer, m, ser)
+}
+
+func (m *_LevelInformationNormal) isLevelInformationNormal() bool {
+	return true
+}
+
+func (m *_LevelInformationNormal) String() string {
+	if m == nil {
+		return "<nil>"
+	}
+	writeBuffer := utils.NewBoxedWriteBufferWithOptions(true, true)
+	if err := writeBuffer.WriteSerializable(m); err != nil {
+		return err.Error()
+	}
+	return writeBuffer.GetBox().String()
+}
diff --git a/plc4j/drivers/c-bus/src/test/java/org/apache/plc4x/java/cbus/ReferenceTest.java b/plc4j/drivers/c-bus/src/test/java/org/apache/plc4x/java/cbus/ReferenceTest.java
index 2c285be48..f05ce16a5 100644
--- a/plc4j/drivers/c-bus/src/test/java/org/apache/plc4x/java/cbus/ReferenceTest.java
+++ b/plc4j/drivers/c-bus/src/test/java/org/apache/plc4x/java/cbus/ReferenceTest.java
@@ -387,7 +387,7 @@ public class ReferenceTest {
         // 7.4
         @Test
         void ExtendedFormatStatusReply1() throws Exception {
-            byte[] bytes = "F9073800AAAA000095990000000005555000000000005555555548\r\n".getBytes(StandardCharsets.UTF_8);
+            byte[] bytes = "F9073800AAAA000095990000000055550000000000005555555548\r\n".getBytes(StandardCharsets.UTF_8);
             ReadBufferByteBased readBufferByteBased = new ReadBufferByteBased(bytes);
             requestContext = new RequestContext(false, true, false);
             cBusOptions = new CBusOptions(false, false, false, true, false, false, false, false, true);
diff --git a/protocols/c-bus/src/main/resources/protocols/cbus/c-bus.mspec b/protocols/c-bus/src/main/resources/protocols/cbus/c-bus.mspec
index a8d48cd66..da627a0b1 100644
--- a/protocols/c-bus/src/main/resources/protocols/cbus/c-bus.mspec
+++ b/protocols/c-bus/src/main/resources/protocols/cbus/c-bus.mspec
@@ -1555,10 +1555,16 @@
     [simple     ApplicationIdContainer
                         application                                 ]
     [simple     uint 8  blockStart                                  ]
+    [virtual    uint 5  numberOfStatusBytes '(coding == StatusCoding.BINARY_BY_THIS_SERIAL_INTERFACE || coding == StatusCoding.BINARY_BY_ELSEWHERE)?(statusHeader.numberOfCharacterPairs - 3):(0)']
+    [virtual    uint 5  numberOfLevelInformation '(coding == StatusCoding.LEVEL_BY_THIS_SERIAL_INTERFACE || coding == StatusCoding.LEVEL_BY_ELSEWHERE)?((statusHeader.numberOfCharacterPairs - 3) / 2):(0)']
     [array      StatusByte
                         statusBytes
-                        count
-                        'statusHeader.numberOfCharacterPairs - 3'   ]
+                            count
+                            'numberOfStatusBytes'                   ]
+    [array      LevelInformation
+                        levelInformation
+                            count
+                            'numberOfLevelInformation'              ]
 ]
 
 [type ExtendedStatusHeader
@@ -1580,6 +1586,53 @@
     [simple GAVState    gav0                                        ]
 ]
 
+[type LevelInformation
+    [peek    uint 16    raw                                         ]
+    [virtual uint 4     nibble1 '(raw & 0xF000) >> 12'              ]
+    [virtual uint 4     nibble2 '(raw & 0x0F00) >> 8'               ]
+    [virtual uint 4     nibble3 '(raw & 0x00F0) >> 4'               ]
+    [virtual uint 4     nibble4 '(raw & 0x000F) >> 0'               ]
+    [virtual bit        isAbsent 'nibble1 == 0x0 && nibble2 == 0x0 && nibble3 == 0x0 && nibble4 == 0x0']
+    [virtual bit        isCorruptedByNoise '!isAbsent && (((nibble1 < 0x5) || (nibble1 == 0x8) || (nibble1 == 0xC)) || ((nibble2 < 0x5) || (nibble2 == 0x8) || (nibble2 == 0xC)) || ((nibble3 < 0x5) || (nibble3 == 0x8) || (nibble3 == 0xC)) || ((nibble4 < 0x5) || (nibble4 == 0x8) || (nibble4 == 0xC)))']
+    [virtual bit        isCorruptedByNoiseOrLevelsDiffer '!isAbsent && (((nibble1 == 0x7) || (nibble1 == 0xB) || (nibble1 > 0xC)) || ((nibble2 == 0x7) || (nibble2 == 0xB) || (nibble2 > 0xC)) || ((nibble3 == 0x7) || (nibble3 == 0xB) || (nibble3 > 0xC)) || ((nibble4 == 0x7) || (nibble4 == 0xB) || (nibble4 > 0xC)))']
+    [virtual bit        isCorrupted 'isCorruptedByNoise || isCorruptedByNoiseOrLevelsDiffer']
+    [typeSwitch isAbsent, isCorrupted
+        ['true'     *Absent
+            [reserved uint 16 '0x0000'                                      ]
+        ]
+        [*, 'true'  *Corrupted
+            [simple  uint 4    corruptedNibble1]
+            [simple  uint 4    corruptedNibble2]
+            [simple  uint 4    corruptedNibble3]
+            [simple  uint 4    corruptedNibble4]
+        ]
+        [*          *Normal
+            [simple  LevelInformationNibblePair  pair1                      ]
+            [simple  LevelInformationNibblePair  pair2                      ]
+            [virtual uint 8  actualLevel 'pair2.nibbleValue << 4 | pair1.nibbleValue']
+        ]
+    ]
+]
+
+[enum uint 8 LevelInformationNibblePair(uint 4 nibbleValue)
+    ['0x55' Value_F ['0xF']]
+    ['0x56' Value_E ['0xE']]
+    ['0x59' Value_D ['0xD']]
+    ['0x5A' Value_C ['0xC']]
+    ['0x65' Value_B ['0xB']]
+    ['0x66' Value_A ['0xA']]
+    ['0x69' Value_9 ['0x9']]
+    ['0x6A' Value_8 ['0x8']]
+    ['0x95' Value_7 ['0x7']]
+    ['0x96' Value_6 ['0x6']]
+    ['0x99' Value_5 ['0x5']]
+    ['0x9A' Value_4 ['0x4']]
+    ['0xA5' Value_3 ['0x3']]
+    ['0xA6' Value_2 ['0x2']]
+    ['0xA9' Value_1 ['0x1']]
+    ['0xAA' Value_0 ['0x0']]
+]
+
 [enum uint 2 GAVState
     ['0' DOES_NOT_EXIST                                             ]
     ['1' ON                                                         ]
diff --git a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/cbus/protocol/CBusServerAdapter.java b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/cbus/protocol/CBusServerAdapter.java
index 48a5f6d46..199dc3ce2 100644
--- a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/cbus/protocol/CBusServerAdapter.java
+++ b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/cbus/protocol/CBusServerAdapter.java
@@ -108,12 +108,12 @@ public class CBusServerAdapter extends ChannelInboundHandlerAdapter {
                     }
                     if (statusRequest instanceof StatusRequestLevel) {
                         StatusRequestLevel statusRequestLevel = (StatusRequestLevel) statusRequest;
-                        ExtendedStatusHeader statusHeader = new ExtendedStatusHeader((short) (3 + 1)); // 2 we have always + 1 as we got one status byte
+                        ExtendedStatusHeader statusHeader = new ExtendedStatusHeader((short) (3 + 2)); // 3 we have always (coding is extra opposed to the standard) + 2 as we got one level information
                         StatusCoding coding = StatusCoding.LEVEL_BY_THIS_SERIAL_INTERFACE;
                         // TODO: map actuall values from simulator
                         byte blockStart = statusRequestLevel.getStartingGroupAddressLabel();
-                        List<StatusByte> statusBytes = List.of(new StatusByte(GAVState.ON, GAVState.ERROR, GAVState.OFF, GAVState.DOES_NOT_EXIST));
-                        ExtendedFormatStatusReply extendedFormatStatusReply = new ExtendedFormatStatusReply(statusHeader, coding, statusRequestLevel.getApplication(), blockStart, statusBytes);
+                        List<LevelInformation> levelInformations = List.of(new LevelInformationNormal(0x5555, LevelInformationNibblePair.Value_F, LevelInformationNibblePair.Value_F));
+                        ExtendedFormatStatusReply extendedFormatStatusReply = new ExtendedFormatStatusReply(statusHeader, coding, statusRequestLevel.getApplication(), blockStart, null, levelInformations);
                         EncodedReply encodedReply = new EncodedReplyExtendedFormatStatusReply((byte) 0xC0, extendedFormatStatusReply, cBusOptions, requestContext);
                         ReplyEncodedReply replyEncodedReply = new ReplyEncodedReply((byte) 0xC0, encodedReply, null, cBusOptions, requestContext);
                         ReplyOrConfirmation replyOrConfirmation = new ReplyOrConfirmationReply((byte) 0xFF, replyEncodedReply, new ResponseTermination(), cBusOptions, requestContext);
@@ -130,7 +130,7 @@ public class CBusServerAdapter extends ChannelInboundHandlerAdapter {
                     // TODO: handle this
                     return;
                 }
-                if (command instanceof  CBusPointToMultiPointCommandNormal) {
+                if (command instanceof CBusPointToMultiPointCommandNormal) {
                     CBusPointToMultiPointCommandNormal cBusPointToMultiPointCommandNormal = (CBusPointToMultiPointCommandNormal) command;
                     LOGGER.info("Handling CBusPointToMultiPointCommandNormal\n{}", cBusPointToMultiPointCommandNormal);
                     return;