You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2021/12/02 12:43:39 UTC

[plc4x] branch develop updated: feat(plc4go/codegen): render virtual fields in boxes

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 13d37b4  feat(plc4go/codegen): render virtual fields in boxes
13d37b4 is described below

commit 13d37b41f29b2211c4e5479824afcf2914b07588
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Thu Dec 2 13:43:30 2021 +0100

    feat(plc4go/codegen): render virtual fields in boxes
---
 .../resources/templates/go/model-template.go.ftlh  |  10 +-
 .../readwrite/model/CIPEncapsulationPacket.go      |   3 +-
 .../abeth/readwrite/model/DF1RequestCommand.go     |   3 +-
 .../abeth/readwrite/model/DF1RequestMessage.go     |   3 +-
 .../abeth/readwrite/model/DF1ResponseMessage.go    |   3 +-
 .../internal/plc4go/ads/readwrite/model/AdsData.go |   3 +-
 .../ads/readwrite/model/AdsMultiRequestItem.go     |   3 +-
 .../plc4go/bacnetip/readwrite/model/APDU.go        |   3 +-
 .../bacnetip/readwrite/model/BACnetComplexTag.go   |  11 +-
 .../readwrite/model/BACnetComplexTagBitString.go   |   4 +
 .../model/BACnetComplexTagCharacterString.go       |   4 +
 .../readwrite/model/BACnetComplexTagDate.go        |  40 ++
 .../readwrite/model/BACnetComplexTagEnumerated.go  |   4 +
 .../readwrite/model/BACnetComplexTagOctetString.go |   4 +
 .../model/BACnetComplexTagSignedInteger.go         |  20 +
 .../readwrite/model/BACnetComplexTagTime.go        |  20 +
 .../model/BACnetComplexTagUnsignedInteger.go       |  16 +
 .../readwrite/model/BACnetConfirmedServiceACK.go   |   3 +-
 .../model/BACnetConfirmedServiceRequest.go         |   3 +-
 .../plc4go/bacnetip/readwrite/model/BACnetError.go |   3 +-
 .../bacnetip/readwrite/model/BACnetServiceAck.go   |   3 +-
 .../plc4go/bacnetip/readwrite/model/BACnetTag.go   |  15 +-
 .../model/BACnetTagApplicationCharacterString.go   |   4 +
 .../readwrite/model/BACnetTagApplicationDate.go    |  44 +++
 .../model/BACnetTagApplicationOctetString.go       |   4 +
 .../model/BACnetTagApplicationSignedInteger.go     |  20 +
 .../readwrite/model/BACnetTagApplicationTime.go    |  20 +
 .../model/BACnetTagApplicationUnsignedInteger.go   |  16 +
 .../model/BACnetUnconfirmedServiceRequest.go       |   3 +-
 .../plc4go/bacnetip/readwrite/model/BVLC.go        |   3 +-
 .../plc4go/bacnetip/readwrite/model/NLM.go         |   3 +-
 .../plc4go/df1/readwrite/model/DF1Command.go       |   3 +-
 .../plc4go/df1/readwrite/model/DF1Symbol.go        |   3 +-
 .../plc4go/eip/readwrite/model/CipService.go       |   3 +-
 .../plc4go/eip/readwrite/model/EipPacket.go        |   3 +-
 .../firmata/readwrite/model/FirmataCommand.go      |   3 +-
 .../firmata/readwrite/model/FirmataMessage.go      |   3 +-
 .../plc4go/firmata/readwrite/model/SysexCommand.go |   3 +-
 .../plc4go/knxnetip/readwrite/model/Apdu.go        |   3 +-
 .../plc4go/knxnetip/readwrite/model/ApduControl.go |   3 +-
 .../plc4go/knxnetip/readwrite/model/ApduData.go    |   3 +-
 .../plc4go/knxnetip/readwrite/model/ApduDataExt.go |   3 +-
 .../plc4go/knxnetip/readwrite/model/CEMI.go        |   3 +-
 .../readwrite/model/CEMIAdditionalInformation.go   |   3 +-
 .../knxnetip/readwrite/model/ComObjectTable.go     |   3 +-
 .../model/ConnectionRequestInformation.go          |   3 +-
 .../readwrite/model/ConnectionResponseDataBlock.go |   3 +-
 .../knxnetip/readwrite/model/KnxGroupAddress.go    |   3 +-
 .../knxnetip/readwrite/model/KnxNetIpMessage.go    |   3 +-
 .../plc4go/knxnetip/readwrite/model/LDataFrame.go  |   3 +-
 .../plc4go/knxnetip/readwrite/model/ServiceId.go   |   3 +-
 .../plc4go/modbus/readwrite/model/ModbusPDU.go     |   3 +-
 .../plc4go/s7/readwrite/model/COTPPacket.go        |   3 +-
 .../plc4go/s7/readwrite/model/COTPParameter.go     |   3 +-
 .../plc4go/s7/readwrite/model/S7Address.go         |   3 +-
 .../s7/readwrite/model/S7DataAlarmMessage.go       |   3 +-
 .../plc4go/s7/readwrite/model/S7Message.go         |   3 +-
 .../plc4go/s7/readwrite/model/S7Parameter.go       |   3 +-
 .../s7/readwrite/model/S7ParameterUserDataItem.go  |   3 +-
 .../plc4go/s7/readwrite/model/S7Payload.go         |   3 +-
 .../s7/readwrite/model/S7PayloadUserDataItem.go    |   3 +-
 .../readwrite/model/S7VarRequestParameterItem.go   |   3 +-
 plc4go/internal/plc4go/spi/utils/WriteBuffer.go    |   1 +
 .../plc4go/spi/utils/WriteBufferBoxBased.go        |  90 +++--
 .../plc4go/spi/utils/WriteBufferByteBased.go       |  13 +-
 .../plc4go/spi/utils/WriteBufferJsonBased.go       |   5 +
 .../plc4go/spi/utils/WriteBufferXmlBased.go        |   5 +
 plc4go/internal/plc4go/spi/utils/asciiBox.go       | 410 ++++++++++++---------
 plc4go/internal/plc4go/spi/utils/asciiBox_test.go  | 295 +++++++--------
 plc4go/internal/plc4go/spi/utils/dumpUtils.go      |  32 +-
 70 files changed, 768 insertions(+), 474 deletions(-)

diff --git a/code-generation/language-go/src/main/resources/templates/go/model-template.go.ftlh b/code-generation/language-go/src/main/resources/templates/go/model-template.go.ftlh
index 0d48d23..54f9d7b 100644
--- a/code-generation/language-go/src/main/resources/templates/go/model-template.go.ftlh
+++ b/code-generation/language-go/src/main/resources/templates/go/model-template.go.ftlh
@@ -1401,12 +1401,18 @@ func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer) error {
 					<#assign switchField = field.asSwitchField().orElseThrow()>
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")<@emitImport import="github.com/pkg/errors" />
 	}
 					<#break>
 				<#case "virtual">
+                	<#assign virtualField = field.asVirtualField().orElseThrow()>
+                	<#assign typedField = field.asTypedField().orElseThrow()>
+                	<#assign namedField = field.asNamedField().orElseThrow()>
+	// Virtual field (doesn't actually serialize anything, just makes the value available)
+	if _${namedField.name}Err := writeBuffer.WriteVirtual("${namedField.name}", m.${namedField.name?cap_first}); _${namedField.name}Err != nil {
+		return errors.Wrap(_${namedField.name}Err, "Error serializing '${namedField.name}' field")<@emitImport import="github.com/pkg/errors" />
+	}
 					<#break>
 			</#switch>
 		</#list>
diff --git a/plc4go/internal/plc4go/abeth/readwrite/model/CIPEncapsulationPacket.go b/plc4go/internal/plc4go/abeth/readwrite/model/CIPEncapsulationPacket.go
index dfdd411..66ca9ab 100644
--- a/plc4go/internal/plc4go/abeth/readwrite/model/CIPEncapsulationPacket.go
+++ b/plc4go/internal/plc4go/abeth/readwrite/model/CIPEncapsulationPacket.go
@@ -288,8 +288,7 @@ func (m *CIPEncapsulationPacket) SerializeParent(writeBuffer utils.WriteBuffer,
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/abeth/readwrite/model/DF1RequestCommand.go b/plc4go/internal/plc4go/abeth/readwrite/model/DF1RequestCommand.go
index 29ef3b3..01578de 100644
--- a/plc4go/internal/plc4go/abeth/readwrite/model/DF1RequestCommand.go
+++ b/plc4go/internal/plc4go/abeth/readwrite/model/DF1RequestCommand.go
@@ -144,8 +144,7 @@ func (m *DF1RequestCommand) SerializeParent(writeBuffer utils.WriteBuffer, child
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/abeth/readwrite/model/DF1RequestMessage.go b/plc4go/internal/plc4go/abeth/readwrite/model/DF1RequestMessage.go
index 4436b56..2c6702b 100644
--- a/plc4go/internal/plc4go/abeth/readwrite/model/DF1RequestMessage.go
+++ b/plc4go/internal/plc4go/abeth/readwrite/model/DF1RequestMessage.go
@@ -242,8 +242,7 @@ func (m *DF1RequestMessage) SerializeParent(writeBuffer utils.WriteBuffer, child
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/abeth/readwrite/model/DF1ResponseMessage.go b/plc4go/internal/plc4go/abeth/readwrite/model/DF1ResponseMessage.go
index ce532e3..f34fc69 100644
--- a/plc4go/internal/plc4go/abeth/readwrite/model/DF1ResponseMessage.go
+++ b/plc4go/internal/plc4go/abeth/readwrite/model/DF1ResponseMessage.go
@@ -267,8 +267,7 @@ func (m *DF1ResponseMessage) SerializeParent(writeBuffer utils.WriteBuffer, chil
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/ads/readwrite/model/AdsData.go b/plc4go/internal/plc4go/ads/readwrite/model/AdsData.go
index 56ee93b..bac59d6 100644
--- a/plc4go/internal/plc4go/ads/readwrite/model/AdsData.go
+++ b/plc4go/internal/plc4go/ads/readwrite/model/AdsData.go
@@ -167,8 +167,7 @@ func (m *AdsData) SerializeParent(writeBuffer utils.WriteBuffer, child IAdsData,
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/ads/readwrite/model/AdsMultiRequestItem.go b/plc4go/internal/plc4go/ads/readwrite/model/AdsMultiRequestItem.go
index 3f2340e..c7164e5 100644
--- a/plc4go/internal/plc4go/ads/readwrite/model/AdsMultiRequestItem.go
+++ b/plc4go/internal/plc4go/ads/readwrite/model/AdsMultiRequestItem.go
@@ -132,8 +132,7 @@ func (m *AdsMultiRequestItem) SerializeParent(writeBuffer utils.WriteBuffer, chi
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/APDU.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/APDU.go
index 2dca357..7917d46 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/APDU.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/APDU.go
@@ -158,8 +158,7 @@ func (m *APDU) SerializeParent(writeBuffer utils.WriteBuffer, child IAPDU, seria
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTag.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTag.go
index 49aec35..c732c03 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTag.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTag.go
@@ -284,6 +284,10 @@ func (m *BACnetComplexTag) SerializeParent(writeBuffer utils.WriteBuffer, child
 			return errors.Wrap(_extTagNumberErr, "Error serializing 'extTagNumber' field")
 		}
 	}
+	// Virtual field (doesn't actually serialize anything, just makes the value available)
+	if _actualTagNumberErr := writeBuffer.WriteVirtual("actualTagNumber", m.ActualTagNumber); _actualTagNumberErr != nil {
+		return errors.Wrap(_actualTagNumberErr, "Error serializing 'actualTagNumber' field")
+	}
 
 	// Optional Field (extLength) (Can be skipped, if the value is null)
 	var extLength *uint8 = nil
@@ -314,10 +318,13 @@ func (m *BACnetComplexTag) SerializeParent(writeBuffer utils.WriteBuffer, child
 			return errors.Wrap(_extExtExtLengthErr, "Error serializing 'extExtExtLength' field")
 		}
 	}
+	// Virtual field (doesn't actually serialize anything, just makes the value available)
+	if _actualLengthErr := writeBuffer.WriteVirtual("actualLength", m.ActualLength); _actualLengthErr != nil {
+		return errors.Wrap(_actualLengthErr, "Error serializing 'actualLength' field")
+	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagBitString.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagBitString.go
index 5ee419f..b04781c 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagBitString.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagBitString.go
@@ -172,6 +172,10 @@ func (m *BACnetComplexTagBitString) Serialize(writeBuffer utils.WriteBuffer) err
 		if pushErr := writeBuffer.PushContext("BACnetComplexTagBitString"); pushErr != nil {
 			return pushErr
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _actualLengthInBitErr := writeBuffer.WriteVirtual("actualLengthInBit", m.ActualLengthInBit); _actualLengthInBitErr != nil {
+			return errors.Wrap(_actualLengthInBitErr, "Error serializing 'actualLengthInBit' field")
+		}
 
 		// Simple Field (unusedBits)
 		unusedBits := uint8(m.UnusedBits)
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagCharacterString.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagCharacterString.go
index 3121e01..13ce1bb 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagCharacterString.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagCharacterString.go
@@ -174,6 +174,10 @@ func (m *BACnetComplexTagCharacterString) Serialize(writeBuffer utils.WriteBuffe
 		if _encodingErr != nil {
 			return errors.Wrap(_encodingErr, "Error serializing 'encoding' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _actualLengthInBitErr := writeBuffer.WriteVirtual("actualLengthInBit", m.ActualLengthInBit); _actualLengthInBitErr != nil {
+			return errors.Wrap(_actualLengthInBitErr, "Error serializing 'actualLengthInBit' field")
+		}
 
 		// Simple Field (value)
 		value := string(m.Value)
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagDate.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagDate.go
index efac7f8..f5b6803 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagDate.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagDate.go
@@ -254,6 +254,10 @@ func (m *BACnetComplexTagDate) Serialize(writeBuffer utils.WriteBuffer) error {
 		if pushErr := writeBuffer.PushContext("BACnetComplexTagDate"); pushErr != nil {
 			return pushErr
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _wildcardErr := writeBuffer.WriteVirtual("wildcard", m.Wildcard); _wildcardErr != nil {
+			return errors.Wrap(_wildcardErr, "Error serializing 'wildcard' field")
+		}
 
 		// Simple Field (yearMinus1900)
 		yearMinus1900 := int8(m.YearMinus1900)
@@ -261,6 +265,10 @@ func (m *BACnetComplexTagDate) Serialize(writeBuffer utils.WriteBuffer) error {
 		if _yearMinus1900Err != nil {
 			return errors.Wrap(_yearMinus1900Err, "Error serializing 'yearMinus1900' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _yearIsWildcardErr := writeBuffer.WriteVirtual("yearIsWildcard", m.YearIsWildcard); _yearIsWildcardErr != nil {
+			return errors.Wrap(_yearIsWildcardErr, "Error serializing 'yearIsWildcard' field")
+		}
 
 		// Simple Field (month)
 		month := int8(m.Month)
@@ -268,6 +276,18 @@ func (m *BACnetComplexTagDate) Serialize(writeBuffer utils.WriteBuffer) error {
 		if _monthErr != nil {
 			return errors.Wrap(_monthErr, "Error serializing 'month' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _monthIsWildcardErr := writeBuffer.WriteVirtual("monthIsWildcard", m.MonthIsWildcard); _monthIsWildcardErr != nil {
+			return errors.Wrap(_monthIsWildcardErr, "Error serializing 'monthIsWildcard' field")
+		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _oddMonthWildcardErr := writeBuffer.WriteVirtual("oddMonthWildcard", m.OddMonthWildcard); _oddMonthWildcardErr != nil {
+			return errors.Wrap(_oddMonthWildcardErr, "Error serializing 'oddMonthWildcard' field")
+		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _evenMonthWildcardErr := writeBuffer.WriteVirtual("evenMonthWildcard", m.EvenMonthWildcard); _evenMonthWildcardErr != nil {
+			return errors.Wrap(_evenMonthWildcardErr, "Error serializing 'evenMonthWildcard' field")
+		}
 
 		// Simple Field (dayOfMonth)
 		dayOfMonth := int8(m.DayOfMonth)
@@ -275,6 +295,22 @@ func (m *BACnetComplexTagDate) Serialize(writeBuffer utils.WriteBuffer) error {
 		if _dayOfMonthErr != nil {
 			return errors.Wrap(_dayOfMonthErr, "Error serializing 'dayOfMonth' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _dayOfMonthIsWildcardErr := writeBuffer.WriteVirtual("dayOfMonthIsWildcard", m.DayOfMonthIsWildcard); _dayOfMonthIsWildcardErr != nil {
+			return errors.Wrap(_dayOfMonthIsWildcardErr, "Error serializing 'dayOfMonthIsWildcard' field")
+		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _lastDayOfMonthWildcardErr := writeBuffer.WriteVirtual("lastDayOfMonthWildcard", m.LastDayOfMonthWildcard); _lastDayOfMonthWildcardErr != nil {
+			return errors.Wrap(_lastDayOfMonthWildcardErr, "Error serializing 'lastDayOfMonthWildcard' field")
+		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _oddDayOfMonthWildcardErr := writeBuffer.WriteVirtual("oddDayOfMonthWildcard", m.OddDayOfMonthWildcard); _oddDayOfMonthWildcardErr != nil {
+			return errors.Wrap(_oddDayOfMonthWildcardErr, "Error serializing 'oddDayOfMonthWildcard' field")
+		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _evenDayOfMonthWildcardErr := writeBuffer.WriteVirtual("evenDayOfMonthWildcard", m.EvenDayOfMonthWildcard); _evenDayOfMonthWildcardErr != nil {
+			return errors.Wrap(_evenDayOfMonthWildcardErr, "Error serializing 'evenDayOfMonthWildcard' field")
+		}
 
 		// Simple Field (dayOfWeek)
 		dayOfWeek := int8(m.DayOfWeek)
@@ -282,6 +318,10 @@ func (m *BACnetComplexTagDate) Serialize(writeBuffer utils.WriteBuffer) error {
 		if _dayOfWeekErr != nil {
 			return errors.Wrap(_dayOfWeekErr, "Error serializing 'dayOfWeek' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _dayOfWeekIsWildcardErr := writeBuffer.WriteVirtual("dayOfWeekIsWildcard", m.DayOfWeekIsWildcard); _dayOfWeekIsWildcardErr != nil {
+			return errors.Wrap(_dayOfWeekIsWildcardErr, "Error serializing 'dayOfWeekIsWildcard' field")
+		}
 
 		if popErr := writeBuffer.PopContext("BACnetComplexTagDate"); popErr != nil {
 			return popErr
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagEnumerated.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagEnumerated.go
index 50282e2..2f30bc1 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagEnumerated.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagEnumerated.go
@@ -159,6 +159,10 @@ func (m *BACnetComplexTagEnumerated) Serialize(writeBuffer utils.WriteBuffer) er
 		if pushErr := writeBuffer.PushContext("BACnetComplexTagEnumerated"); pushErr != nil {
 			return pushErr
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _actualLengthInBitErr := writeBuffer.WriteVirtual("actualLengthInBit", m.ActualLengthInBit); _actualLengthInBitErr != nil {
+			return errors.Wrap(_actualLengthInBitErr, "Error serializing 'actualLengthInBit' field")
+		}
 
 		// Array Field (data)
 		if m.Data != nil {
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagOctetString.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagOctetString.go
index 278ae76..7ef4169 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagOctetString.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagOctetString.go
@@ -143,6 +143,10 @@ func (m *BACnetComplexTagOctetString) Serialize(writeBuffer utils.WriteBuffer) e
 		if pushErr := writeBuffer.PushContext("BACnetComplexTagOctetString"); pushErr != nil {
 			return pushErr
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _actualLengthInBitErr := writeBuffer.WriteVirtual("actualLengthInBit", m.ActualLengthInBit); _actualLengthInBitErr != nil {
+			return errors.Wrap(_actualLengthInBitErr, "Error serializing 'actualLengthInBit' field")
+		}
 
 		// Simple Field (value)
 		value := string(m.Value)
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagSignedInteger.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagSignedInteger.go
index d21efad..e0c79d7 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagSignedInteger.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagSignedInteger.go
@@ -238,6 +238,10 @@ func (m *BACnetComplexTagSignedInteger) Serialize(writeBuffer utils.WriteBuffer)
 		if pushErr := writeBuffer.PushContext("BACnetComplexTagSignedInteger"); pushErr != nil {
 			return pushErr
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _isInt8Err := writeBuffer.WriteVirtual("isInt8", m.IsInt8); _isInt8Err != nil {
+			return errors.Wrap(_isInt8Err, "Error serializing 'isInt8' field")
+		}
 
 		// Optional Field (valueInt8) (Can be skipped, if the value is null)
 		var valueInt8 *int8 = nil
@@ -248,6 +252,10 @@ func (m *BACnetComplexTagSignedInteger) Serialize(writeBuffer utils.WriteBuffer)
 				return errors.Wrap(_valueInt8Err, "Error serializing 'valueInt8' field")
 			}
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _isInt16Err := writeBuffer.WriteVirtual("isInt16", m.IsInt16); _isInt16Err != nil {
+			return errors.Wrap(_isInt16Err, "Error serializing 'isInt16' field")
+		}
 
 		// Optional Field (valueInt16) (Can be skipped, if the value is null)
 		var valueInt16 *int16 = nil
@@ -258,6 +266,10 @@ func (m *BACnetComplexTagSignedInteger) Serialize(writeBuffer utils.WriteBuffer)
 				return errors.Wrap(_valueInt16Err, "Error serializing 'valueInt16' field")
 			}
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _isInt32Err := writeBuffer.WriteVirtual("isInt32", m.IsInt32); _isInt32Err != nil {
+			return errors.Wrap(_isInt32Err, "Error serializing 'isInt32' field")
+		}
 
 		// Optional Field (valueInt32) (Can be skipped, if the value is null)
 		var valueInt32 *int32 = nil
@@ -268,6 +280,10 @@ func (m *BACnetComplexTagSignedInteger) Serialize(writeBuffer utils.WriteBuffer)
 				return errors.Wrap(_valueInt32Err, "Error serializing 'valueInt32' field")
 			}
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _isInt64Err := writeBuffer.WriteVirtual("isInt64", m.IsInt64); _isInt64Err != nil {
+			return errors.Wrap(_isInt64Err, "Error serializing 'isInt64' field")
+		}
 
 		// Optional Field (valueInt64) (Can be skipped, if the value is null)
 		var valueInt64 *int64 = nil
@@ -278,6 +294,10 @@ func (m *BACnetComplexTagSignedInteger) Serialize(writeBuffer utils.WriteBuffer)
 				return errors.Wrap(_valueInt64Err, "Error serializing 'valueInt64' field")
 			}
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _actualValueErr := writeBuffer.WriteVirtual("actualValue", m.ActualValue); _actualValueErr != nil {
+			return errors.Wrap(_actualValueErr, "Error serializing 'actualValue' field")
+		}
 
 		if popErr := writeBuffer.PopContext("BACnetComplexTagSignedInteger"); popErr != nil {
 			return popErr
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagTime.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagTime.go
index 806503f..22531b3 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagTime.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagTime.go
@@ -214,6 +214,10 @@ func (m *BACnetComplexTagTime) Serialize(writeBuffer utils.WriteBuffer) error {
 		if pushErr := writeBuffer.PushContext("BACnetComplexTagTime"); pushErr != nil {
 			return pushErr
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _wildcardErr := writeBuffer.WriteVirtual("wildcard", m.Wildcard); _wildcardErr != nil {
+			return errors.Wrap(_wildcardErr, "Error serializing 'wildcard' field")
+		}
 
 		// Simple Field (hour)
 		hour := int8(m.Hour)
@@ -221,6 +225,10 @@ func (m *BACnetComplexTagTime) Serialize(writeBuffer utils.WriteBuffer) error {
 		if _hourErr != nil {
 			return errors.Wrap(_hourErr, "Error serializing 'hour' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _hourIsWildcardErr := writeBuffer.WriteVirtual("hourIsWildcard", m.HourIsWildcard); _hourIsWildcardErr != nil {
+			return errors.Wrap(_hourIsWildcardErr, "Error serializing 'hourIsWildcard' field")
+		}
 
 		// Simple Field (minute)
 		minute := int8(m.Minute)
@@ -228,6 +236,10 @@ func (m *BACnetComplexTagTime) Serialize(writeBuffer utils.WriteBuffer) error {
 		if _minuteErr != nil {
 			return errors.Wrap(_minuteErr, "Error serializing 'minute' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _minuteIsWildcardErr := writeBuffer.WriteVirtual("minuteIsWildcard", m.MinuteIsWildcard); _minuteIsWildcardErr != nil {
+			return errors.Wrap(_minuteIsWildcardErr, "Error serializing 'minuteIsWildcard' field")
+		}
 
 		// Simple Field (second)
 		second := int8(m.Second)
@@ -235,6 +247,10 @@ func (m *BACnetComplexTagTime) Serialize(writeBuffer utils.WriteBuffer) error {
 		if _secondErr != nil {
 			return errors.Wrap(_secondErr, "Error serializing 'second' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _secondIsWildcardErr := writeBuffer.WriteVirtual("secondIsWildcard", m.SecondIsWildcard); _secondIsWildcardErr != nil {
+			return errors.Wrap(_secondIsWildcardErr, "Error serializing 'secondIsWildcard' field")
+		}
 
 		// Simple Field (fractional)
 		fractional := int8(m.Fractional)
@@ -242,6 +258,10 @@ func (m *BACnetComplexTagTime) Serialize(writeBuffer utils.WriteBuffer) error {
 		if _fractionalErr != nil {
 			return errors.Wrap(_fractionalErr, "Error serializing 'fractional' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _fractionalIsWildcardErr := writeBuffer.WriteVirtual("fractionalIsWildcard", m.FractionalIsWildcard); _fractionalIsWildcardErr != nil {
+			return errors.Wrap(_fractionalIsWildcardErr, "Error serializing 'fractionalIsWildcard' field")
+		}
 
 		if popErr := writeBuffer.PopContext("BACnetComplexTagTime"); popErr != nil {
 			return popErr
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagUnsignedInteger.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagUnsignedInteger.go
index 11c7a43..5805672 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagUnsignedInteger.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetComplexTagUnsignedInteger.go
@@ -212,6 +212,10 @@ func (m *BACnetComplexTagUnsignedInteger) Serialize(writeBuffer utils.WriteBuffe
 		if pushErr := writeBuffer.PushContext("BACnetComplexTagUnsignedInteger"); pushErr != nil {
 			return pushErr
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _isUint8Err := writeBuffer.WriteVirtual("isUint8", m.IsUint8); _isUint8Err != nil {
+			return errors.Wrap(_isUint8Err, "Error serializing 'isUint8' field")
+		}
 
 		// Optional Field (valueUint8) (Can be skipped, if the value is null)
 		var valueUint8 *uint8 = nil
@@ -222,6 +226,10 @@ func (m *BACnetComplexTagUnsignedInteger) Serialize(writeBuffer utils.WriteBuffe
 				return errors.Wrap(_valueUint8Err, "Error serializing 'valueUint8' field")
 			}
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _isUint16Err := writeBuffer.WriteVirtual("isUint16", m.IsUint16); _isUint16Err != nil {
+			return errors.Wrap(_isUint16Err, "Error serializing 'isUint16' field")
+		}
 
 		// Optional Field (valueUint16) (Can be skipped, if the value is null)
 		var valueUint16 *uint16 = nil
@@ -232,6 +240,10 @@ func (m *BACnetComplexTagUnsignedInteger) Serialize(writeBuffer utils.WriteBuffe
 				return errors.Wrap(_valueUint16Err, "Error serializing 'valueUint16' field")
 			}
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _isUint32Err := writeBuffer.WriteVirtual("isUint32", m.IsUint32); _isUint32Err != nil {
+			return errors.Wrap(_isUint32Err, "Error serializing 'isUint32' field")
+		}
 
 		// Optional Field (valueUint32) (Can be skipped, if the value is null)
 		var valueUint32 *uint32 = nil
@@ -242,6 +254,10 @@ func (m *BACnetComplexTagUnsignedInteger) Serialize(writeBuffer utils.WriteBuffe
 				return errors.Wrap(_valueUint32Err, "Error serializing 'valueUint32' field")
 			}
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _actualValueErr := writeBuffer.WriteVirtual("actualValue", m.ActualValue); _actualValueErr != nil {
+			return errors.Wrap(_actualValueErr, "Error serializing 'actualValue' field")
+		}
 
 		if popErr := writeBuffer.PopContext("BACnetComplexTagUnsignedInteger"); popErr != nil {
 			return popErr
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConfirmedServiceACK.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConfirmedServiceACK.go
index 2576449..a0a8f45 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConfirmedServiceACK.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConfirmedServiceACK.go
@@ -170,8 +170,7 @@ func (m *BACnetConfirmedServiceACK) SerializeParent(writeBuffer utils.WriteBuffe
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConfirmedServiceRequest.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConfirmedServiceRequest.go
index 7857ae5..44220c3 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConfirmedServiceRequest.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetConfirmedServiceRequest.go
@@ -204,8 +204,7 @@ func (m *BACnetConfirmedServiceRequest) SerializeParent(writeBuffer utils.WriteB
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetError.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetError.go
index b7eccbf..77a6ffd 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetError.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetError.go
@@ -172,8 +172,7 @@ func (m *BACnetError) SerializeParent(writeBuffer utils.WriteBuffer, child IBACn
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetServiceAck.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetServiceAck.go
index 3e60750..4593d31 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetServiceAck.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetServiceAck.go
@@ -170,8 +170,7 @@ func (m *BACnetServiceAck) SerializeParent(writeBuffer utils.WriteBuffer, child
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTag.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTag.go
index 5995cae..3347111 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTag.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTag.go
@@ -306,6 +306,14 @@ func (m *BACnetTag) SerializeParent(writeBuffer utils.WriteBuffer, child IBACnet
 			return errors.Wrap(_extTagNumberErr, "Error serializing 'extTagNumber' field")
 		}
 	}
+	// Virtual field (doesn't actually serialize anything, just makes the value available)
+	if _actualTagNumberErr := writeBuffer.WriteVirtual("actualTagNumber", m.ActualTagNumber); _actualTagNumberErr != nil {
+		return errors.Wrap(_actualTagNumberErr, "Error serializing 'actualTagNumber' field")
+	}
+	// Virtual field (doesn't actually serialize anything, just makes the value available)
+	if _isPrimitiveAndNotBooleanErr := writeBuffer.WriteVirtual("isPrimitiveAndNotBoolean", m.IsPrimitiveAndNotBoolean); _isPrimitiveAndNotBooleanErr != nil {
+		return errors.Wrap(_isPrimitiveAndNotBooleanErr, "Error serializing 'isPrimitiveAndNotBoolean' field")
+	}
 
 	// Optional Field (extLength) (Can be skipped, if the value is null)
 	var extLength *uint8 = nil
@@ -336,10 +344,13 @@ func (m *BACnetTag) SerializeParent(writeBuffer utils.WriteBuffer, child IBACnet
 			return errors.Wrap(_extExtExtLengthErr, "Error serializing 'extExtExtLength' field")
 		}
 	}
+	// Virtual field (doesn't actually serialize anything, just makes the value available)
+	if _actualLengthErr := writeBuffer.WriteVirtual("actualLength", m.ActualLength); _actualLengthErr != nil {
+		return errors.Wrap(_actualLengthErr, "Error serializing 'actualLength' field")
+	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationCharacterString.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationCharacterString.go
index a8d2a5e..f5a0352 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationCharacterString.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationCharacterString.go
@@ -173,6 +173,10 @@ func (m *BACnetTagApplicationCharacterString) Serialize(writeBuffer utils.WriteB
 		if _encodingErr != nil {
 			return errors.Wrap(_encodingErr, "Error serializing 'encoding' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _actualLengthInBitErr := writeBuffer.WriteVirtual("actualLengthInBit", m.ActualLengthInBit); _actualLengthInBitErr != nil {
+			return errors.Wrap(_actualLengthInBitErr, "Error serializing 'actualLengthInBit' field")
+		}
 
 		// Simple Field (value)
 		value := string(m.Value)
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationDate.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationDate.go
index 145a2ed..2e64ca6 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationDate.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationDate.go
@@ -261,6 +261,10 @@ func (m *BACnetTagApplicationDate) Serialize(writeBuffer utils.WriteBuffer) erro
 		if pushErr := writeBuffer.PushContext("BACnetTagApplicationDate"); pushErr != nil {
 			return pushErr
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _wildcardErr := writeBuffer.WriteVirtual("wildcard", m.Wildcard); _wildcardErr != nil {
+			return errors.Wrap(_wildcardErr, "Error serializing 'wildcard' field")
+		}
 
 		// Simple Field (yearMinus1900)
 		yearMinus1900 := int8(m.YearMinus1900)
@@ -268,6 +272,14 @@ func (m *BACnetTagApplicationDate) Serialize(writeBuffer utils.WriteBuffer) erro
 		if _yearMinus1900Err != nil {
 			return errors.Wrap(_yearMinus1900Err, "Error serializing 'yearMinus1900' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _yearIsWildcardErr := writeBuffer.WriteVirtual("yearIsWildcard", m.YearIsWildcard); _yearIsWildcardErr != nil {
+			return errors.Wrap(_yearIsWildcardErr, "Error serializing 'yearIsWildcard' field")
+		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _yearErr := writeBuffer.WriteVirtual("year", m.Year); _yearErr != nil {
+			return errors.Wrap(_yearErr, "Error serializing 'year' field")
+		}
 
 		// Simple Field (month)
 		month := int8(m.Month)
@@ -275,6 +287,18 @@ func (m *BACnetTagApplicationDate) Serialize(writeBuffer utils.WriteBuffer) erro
 		if _monthErr != nil {
 			return errors.Wrap(_monthErr, "Error serializing 'month' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _monthIsWildcardErr := writeBuffer.WriteVirtual("monthIsWildcard", m.MonthIsWildcard); _monthIsWildcardErr != nil {
+			return errors.Wrap(_monthIsWildcardErr, "Error serializing 'monthIsWildcard' field")
+		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _oddMonthWildcardErr := writeBuffer.WriteVirtual("oddMonthWildcard", m.OddMonthWildcard); _oddMonthWildcardErr != nil {
+			return errors.Wrap(_oddMonthWildcardErr, "Error serializing 'oddMonthWildcard' field")
+		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _evenMonthWildcardErr := writeBuffer.WriteVirtual("evenMonthWildcard", m.EvenMonthWildcard); _evenMonthWildcardErr != nil {
+			return errors.Wrap(_evenMonthWildcardErr, "Error serializing 'evenMonthWildcard' field")
+		}
 
 		// Simple Field (dayOfMonth)
 		dayOfMonth := int8(m.DayOfMonth)
@@ -282,6 +306,22 @@ func (m *BACnetTagApplicationDate) Serialize(writeBuffer utils.WriteBuffer) erro
 		if _dayOfMonthErr != nil {
 			return errors.Wrap(_dayOfMonthErr, "Error serializing 'dayOfMonth' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _dayOfMonthIsWildcardErr := writeBuffer.WriteVirtual("dayOfMonthIsWildcard", m.DayOfMonthIsWildcard); _dayOfMonthIsWildcardErr != nil {
+			return errors.Wrap(_dayOfMonthIsWildcardErr, "Error serializing 'dayOfMonthIsWildcard' field")
+		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _lastDayOfMonthWildcardErr := writeBuffer.WriteVirtual("lastDayOfMonthWildcard", m.LastDayOfMonthWildcard); _lastDayOfMonthWildcardErr != nil {
+			return errors.Wrap(_lastDayOfMonthWildcardErr, "Error serializing 'lastDayOfMonthWildcard' field")
+		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _oddDayOfMonthWildcardErr := writeBuffer.WriteVirtual("oddDayOfMonthWildcard", m.OddDayOfMonthWildcard); _oddDayOfMonthWildcardErr != nil {
+			return errors.Wrap(_oddDayOfMonthWildcardErr, "Error serializing 'oddDayOfMonthWildcard' field")
+		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _evenDayOfMonthWildcardErr := writeBuffer.WriteVirtual("evenDayOfMonthWildcard", m.EvenDayOfMonthWildcard); _evenDayOfMonthWildcardErr != nil {
+			return errors.Wrap(_evenDayOfMonthWildcardErr, "Error serializing 'evenDayOfMonthWildcard' field")
+		}
 
 		// Simple Field (dayOfWeek)
 		dayOfWeek := int8(m.DayOfWeek)
@@ -289,6 +329,10 @@ func (m *BACnetTagApplicationDate) Serialize(writeBuffer utils.WriteBuffer) erro
 		if _dayOfWeekErr != nil {
 			return errors.Wrap(_dayOfWeekErr, "Error serializing 'dayOfWeek' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _dayOfWeekIsWildcardErr := writeBuffer.WriteVirtual("dayOfWeekIsWildcard", m.DayOfWeekIsWildcard); _dayOfWeekIsWildcardErr != nil {
+			return errors.Wrap(_dayOfWeekIsWildcardErr, "Error serializing 'dayOfWeekIsWildcard' field")
+		}
 
 		if popErr := writeBuffer.PopContext("BACnetTagApplicationDate"); popErr != nil {
 			return popErr
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationOctetString.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationOctetString.go
index 3d2e195..2d70b32 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationOctetString.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationOctetString.go
@@ -142,6 +142,10 @@ func (m *BACnetTagApplicationOctetString) Serialize(writeBuffer utils.WriteBuffe
 		if pushErr := writeBuffer.PushContext("BACnetTagApplicationOctetString"); pushErr != nil {
 			return pushErr
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _actualLengthInBitErr := writeBuffer.WriteVirtual("actualLengthInBit", m.ActualLengthInBit); _actualLengthInBitErr != nil {
+			return errors.Wrap(_actualLengthInBitErr, "Error serializing 'actualLengthInBit' field")
+		}
 
 		// Simple Field (value)
 		value := string(m.Value)
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationSignedInteger.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationSignedInteger.go
index 7857632..3bcffad 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationSignedInteger.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationSignedInteger.go
@@ -237,6 +237,10 @@ func (m *BACnetTagApplicationSignedInteger) Serialize(writeBuffer utils.WriteBuf
 		if pushErr := writeBuffer.PushContext("BACnetTagApplicationSignedInteger"); pushErr != nil {
 			return pushErr
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _isInt8Err := writeBuffer.WriteVirtual("isInt8", m.IsInt8); _isInt8Err != nil {
+			return errors.Wrap(_isInt8Err, "Error serializing 'isInt8' field")
+		}
 
 		// Optional Field (valueInt8) (Can be skipped, if the value is null)
 		var valueInt8 *int8 = nil
@@ -247,6 +251,10 @@ func (m *BACnetTagApplicationSignedInteger) Serialize(writeBuffer utils.WriteBuf
 				return errors.Wrap(_valueInt8Err, "Error serializing 'valueInt8' field")
 			}
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _isInt16Err := writeBuffer.WriteVirtual("isInt16", m.IsInt16); _isInt16Err != nil {
+			return errors.Wrap(_isInt16Err, "Error serializing 'isInt16' field")
+		}
 
 		// Optional Field (valueInt16) (Can be skipped, if the value is null)
 		var valueInt16 *int16 = nil
@@ -257,6 +265,10 @@ func (m *BACnetTagApplicationSignedInteger) Serialize(writeBuffer utils.WriteBuf
 				return errors.Wrap(_valueInt16Err, "Error serializing 'valueInt16' field")
 			}
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _isInt32Err := writeBuffer.WriteVirtual("isInt32", m.IsInt32); _isInt32Err != nil {
+			return errors.Wrap(_isInt32Err, "Error serializing 'isInt32' field")
+		}
 
 		// Optional Field (valueInt32) (Can be skipped, if the value is null)
 		var valueInt32 *int32 = nil
@@ -267,6 +279,10 @@ func (m *BACnetTagApplicationSignedInteger) Serialize(writeBuffer utils.WriteBuf
 				return errors.Wrap(_valueInt32Err, "Error serializing 'valueInt32' field")
 			}
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _isInt64Err := writeBuffer.WriteVirtual("isInt64", m.IsInt64); _isInt64Err != nil {
+			return errors.Wrap(_isInt64Err, "Error serializing 'isInt64' field")
+		}
 
 		// Optional Field (valueInt64) (Can be skipped, if the value is null)
 		var valueInt64 *int64 = nil
@@ -277,6 +293,10 @@ func (m *BACnetTagApplicationSignedInteger) Serialize(writeBuffer utils.WriteBuf
 				return errors.Wrap(_valueInt64Err, "Error serializing 'valueInt64' field")
 			}
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _actualValueErr := writeBuffer.WriteVirtual("actualValue", m.ActualValue); _actualValueErr != nil {
+			return errors.Wrap(_actualValueErr, "Error serializing 'actualValue' field")
+		}
 
 		if popErr := writeBuffer.PopContext("BACnetTagApplicationSignedInteger"); popErr != nil {
 			return popErr
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationTime.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationTime.go
index 516ad32..21d4a65 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationTime.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationTime.go
@@ -213,6 +213,10 @@ func (m *BACnetTagApplicationTime) Serialize(writeBuffer utils.WriteBuffer) erro
 		if pushErr := writeBuffer.PushContext("BACnetTagApplicationTime"); pushErr != nil {
 			return pushErr
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _wildcardErr := writeBuffer.WriteVirtual("wildcard", m.Wildcard); _wildcardErr != nil {
+			return errors.Wrap(_wildcardErr, "Error serializing 'wildcard' field")
+		}
 
 		// Simple Field (hour)
 		hour := int8(m.Hour)
@@ -220,6 +224,10 @@ func (m *BACnetTagApplicationTime) Serialize(writeBuffer utils.WriteBuffer) erro
 		if _hourErr != nil {
 			return errors.Wrap(_hourErr, "Error serializing 'hour' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _hourIsWildcardErr := writeBuffer.WriteVirtual("hourIsWildcard", m.HourIsWildcard); _hourIsWildcardErr != nil {
+			return errors.Wrap(_hourIsWildcardErr, "Error serializing 'hourIsWildcard' field")
+		}
 
 		// Simple Field (minute)
 		minute := int8(m.Minute)
@@ -227,6 +235,10 @@ func (m *BACnetTagApplicationTime) Serialize(writeBuffer utils.WriteBuffer) erro
 		if _minuteErr != nil {
 			return errors.Wrap(_minuteErr, "Error serializing 'minute' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _minuteIsWildcardErr := writeBuffer.WriteVirtual("minuteIsWildcard", m.MinuteIsWildcard); _minuteIsWildcardErr != nil {
+			return errors.Wrap(_minuteIsWildcardErr, "Error serializing 'minuteIsWildcard' field")
+		}
 
 		// Simple Field (second)
 		second := int8(m.Second)
@@ -234,6 +246,10 @@ func (m *BACnetTagApplicationTime) Serialize(writeBuffer utils.WriteBuffer) erro
 		if _secondErr != nil {
 			return errors.Wrap(_secondErr, "Error serializing 'second' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _secondIsWildcardErr := writeBuffer.WriteVirtual("secondIsWildcard", m.SecondIsWildcard); _secondIsWildcardErr != nil {
+			return errors.Wrap(_secondIsWildcardErr, "Error serializing 'secondIsWildcard' field")
+		}
 
 		// Simple Field (fractional)
 		fractional := int8(m.Fractional)
@@ -241,6 +257,10 @@ func (m *BACnetTagApplicationTime) Serialize(writeBuffer utils.WriteBuffer) erro
 		if _fractionalErr != nil {
 			return errors.Wrap(_fractionalErr, "Error serializing 'fractional' field")
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _fractionalIsWildcardErr := writeBuffer.WriteVirtual("fractionalIsWildcard", m.FractionalIsWildcard); _fractionalIsWildcardErr != nil {
+			return errors.Wrap(_fractionalIsWildcardErr, "Error serializing 'fractionalIsWildcard' field")
+		}
 
 		if popErr := writeBuffer.PopContext("BACnetTagApplicationTime"); popErr != nil {
 			return popErr
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationUnsignedInteger.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationUnsignedInteger.go
index 94c9227..a1c019f 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationUnsignedInteger.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetTagApplicationUnsignedInteger.go
@@ -211,6 +211,10 @@ func (m *BACnetTagApplicationUnsignedInteger) Serialize(writeBuffer utils.WriteB
 		if pushErr := writeBuffer.PushContext("BACnetTagApplicationUnsignedInteger"); pushErr != nil {
 			return pushErr
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _isUint8Err := writeBuffer.WriteVirtual("isUint8", m.IsUint8); _isUint8Err != nil {
+			return errors.Wrap(_isUint8Err, "Error serializing 'isUint8' field")
+		}
 
 		// Optional Field (valueUint8) (Can be skipped, if the value is null)
 		var valueUint8 *uint8 = nil
@@ -221,6 +225,10 @@ func (m *BACnetTagApplicationUnsignedInteger) Serialize(writeBuffer utils.WriteB
 				return errors.Wrap(_valueUint8Err, "Error serializing 'valueUint8' field")
 			}
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _isUint16Err := writeBuffer.WriteVirtual("isUint16", m.IsUint16); _isUint16Err != nil {
+			return errors.Wrap(_isUint16Err, "Error serializing 'isUint16' field")
+		}
 
 		// Optional Field (valueUint16) (Can be skipped, if the value is null)
 		var valueUint16 *uint16 = nil
@@ -231,6 +239,10 @@ func (m *BACnetTagApplicationUnsignedInteger) Serialize(writeBuffer utils.WriteB
 				return errors.Wrap(_valueUint16Err, "Error serializing 'valueUint16' field")
 			}
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _isUint32Err := writeBuffer.WriteVirtual("isUint32", m.IsUint32); _isUint32Err != nil {
+			return errors.Wrap(_isUint32Err, "Error serializing 'isUint32' field")
+		}
 
 		// Optional Field (valueUint32) (Can be skipped, if the value is null)
 		var valueUint32 *uint32 = nil
@@ -241,6 +253,10 @@ func (m *BACnetTagApplicationUnsignedInteger) Serialize(writeBuffer utils.WriteB
 				return errors.Wrap(_valueUint32Err, "Error serializing 'valueUint32' field")
 			}
 		}
+		// Virtual field (doesn't actually serialize anything, just makes the value available)
+		if _actualValueErr := writeBuffer.WriteVirtual("actualValue", m.ActualValue); _actualValueErr != nil {
+			return errors.Wrap(_actualValueErr, "Error serializing 'actualValue' field")
+		}
 
 		if popErr := writeBuffer.PopContext("BACnetTagApplicationUnsignedInteger"); popErr != nil {
 			return popErr
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetUnconfirmedServiceRequest.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetUnconfirmedServiceRequest.go
index ba306dc..d420559 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetUnconfirmedServiceRequest.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BACnetUnconfirmedServiceRequest.go
@@ -166,8 +166,7 @@ func (m *BACnetUnconfirmedServiceRequest) SerializeParent(writeBuffer utils.Writ
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/BVLC.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/BVLC.go
index 2123830..b643f27 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/BVLC.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/BVLC.go
@@ -207,8 +207,7 @@ func (m *BVLC) SerializeParent(writeBuffer utils.WriteBuffer, child IBVLC, seria
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/bacnetip/readwrite/model/NLM.go b/plc4go/internal/plc4go/bacnetip/readwrite/model/NLM.go
index 641d383..90dbb59 100644
--- a/plc4go/internal/plc4go/bacnetip/readwrite/model/NLM.go
+++ b/plc4go/internal/plc4go/bacnetip/readwrite/model/NLM.go
@@ -172,8 +172,7 @@ func (m *NLM) SerializeParent(writeBuffer utils.WriteBuffer, child INLM, seriali
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/df1/readwrite/model/DF1Command.go b/plc4go/internal/plc4go/df1/readwrite/model/DF1Command.go
index 751020a..71fc75c 100644
--- a/plc4go/internal/plc4go/df1/readwrite/model/DF1Command.go
+++ b/plc4go/internal/plc4go/df1/readwrite/model/DF1Command.go
@@ -182,8 +182,7 @@ func (m *DF1Command) SerializeParent(writeBuffer utils.WriteBuffer, child IDF1Co
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/df1/readwrite/model/DF1Symbol.go b/plc4go/internal/plc4go/df1/readwrite/model/DF1Symbol.go
index a58abaa..aed2c42 100644
--- a/plc4go/internal/plc4go/df1/readwrite/model/DF1Symbol.go
+++ b/plc4go/internal/plc4go/df1/readwrite/model/DF1Symbol.go
@@ -170,8 +170,7 @@ func (m *DF1Symbol) SerializeParent(writeBuffer utils.WriteBuffer, child IDF1Sym
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/eip/readwrite/model/CipService.go b/plc4go/internal/plc4go/eip/readwrite/model/CipService.go
index 0138830..75f61d0 100644
--- a/plc4go/internal/plc4go/eip/readwrite/model/CipService.go
+++ b/plc4go/internal/plc4go/eip/readwrite/model/CipService.go
@@ -156,8 +156,7 @@ func (m *CipService) SerializeParent(writeBuffer utils.WriteBuffer, child ICipSe
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/eip/readwrite/model/EipPacket.go b/plc4go/internal/plc4go/eip/readwrite/model/EipPacket.go
index 918bd6b..bd8a061 100644
--- a/plc4go/internal/plc4go/eip/readwrite/model/EipPacket.go
+++ b/plc4go/internal/plc4go/eip/readwrite/model/EipPacket.go
@@ -260,8 +260,7 @@ func (m *EipPacket) SerializeParent(writeBuffer utils.WriteBuffer, child IEipPac
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/firmata/readwrite/model/FirmataCommand.go b/plc4go/internal/plc4go/firmata/readwrite/model/FirmataCommand.go
index bb35b9a..4471f11 100644
--- a/plc4go/internal/plc4go/firmata/readwrite/model/FirmataCommand.go
+++ b/plc4go/internal/plc4go/firmata/readwrite/model/FirmataCommand.go
@@ -152,8 +152,7 @@ func (m *FirmataCommand) SerializeParent(writeBuffer utils.WriteBuffer, child IF
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/firmata/readwrite/model/FirmataMessage.go b/plc4go/internal/plc4go/firmata/readwrite/model/FirmataMessage.go
index 4bafe55..16dd553 100644
--- a/plc4go/internal/plc4go/firmata/readwrite/model/FirmataMessage.go
+++ b/plc4go/internal/plc4go/firmata/readwrite/model/FirmataMessage.go
@@ -152,8 +152,7 @@ func (m *FirmataMessage) SerializeParent(writeBuffer utils.WriteBuffer, child IF
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/firmata/readwrite/model/SysexCommand.go b/plc4go/internal/plc4go/firmata/readwrite/model/SysexCommand.go
index e00849a..a1adb12 100644
--- a/plc4go/internal/plc4go/firmata/readwrite/model/SysexCommand.go
+++ b/plc4go/internal/plc4go/firmata/readwrite/model/SysexCommand.go
@@ -173,8 +173,7 @@ func (m *SysexCommand) SerializeParent(writeBuffer utils.WriteBuffer, child ISys
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/knxnetip/readwrite/model/Apdu.go b/plc4go/internal/plc4go/knxnetip/readwrite/model/Apdu.go
index e5fb91a..b02f30d 100644
--- a/plc4go/internal/plc4go/knxnetip/readwrite/model/Apdu.go
+++ b/plc4go/internal/plc4go/knxnetip/readwrite/model/Apdu.go
@@ -182,8 +182,7 @@ func (m *Apdu) SerializeParent(writeBuffer utils.WriteBuffer, child IApdu, seria
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/knxnetip/readwrite/model/ApduControl.go b/plc4go/internal/plc4go/knxnetip/readwrite/model/ApduControl.go
index 44a2eef..e54408f 100644
--- a/plc4go/internal/plc4go/knxnetip/readwrite/model/ApduControl.go
+++ b/plc4go/internal/plc4go/knxnetip/readwrite/model/ApduControl.go
@@ -150,8 +150,7 @@ func (m *ApduControl) SerializeParent(writeBuffer utils.WriteBuffer, child IApdu
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/knxnetip/readwrite/model/ApduData.go b/plc4go/internal/plc4go/knxnetip/readwrite/model/ApduData.go
index dfaebc3..38689f0 100644
--- a/plc4go/internal/plc4go/knxnetip/readwrite/model/ApduData.go
+++ b/plc4go/internal/plc4go/knxnetip/readwrite/model/ApduData.go
@@ -174,8 +174,7 @@ func (m *ApduData) SerializeParent(writeBuffer utils.WriteBuffer, child IApduDat
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/knxnetip/readwrite/model/ApduDataExt.go b/plc4go/internal/plc4go/knxnetip/readwrite/model/ApduDataExt.go
index baaeda3..08296b1 100644
--- a/plc4go/internal/plc4go/knxnetip/readwrite/model/ApduDataExt.go
+++ b/plc4go/internal/plc4go/knxnetip/readwrite/model/ApduDataExt.go
@@ -224,8 +224,7 @@ func (m *ApduDataExt) SerializeParent(writeBuffer utils.WriteBuffer, child IApdu
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/knxnetip/readwrite/model/CEMI.go b/plc4go/internal/plc4go/knxnetip/readwrite/model/CEMI.go
index 82b3146..b3efe60 100644
--- a/plc4go/internal/plc4go/knxnetip/readwrite/model/CEMI.go
+++ b/plc4go/internal/plc4go/knxnetip/readwrite/model/CEMI.go
@@ -188,8 +188,7 @@ func (m *CEMI) SerializeParent(writeBuffer utils.WriteBuffer, child ICEMI, seria
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/knxnetip/readwrite/model/CEMIAdditionalInformation.go b/plc4go/internal/plc4go/knxnetip/readwrite/model/CEMIAdditionalInformation.go
index 5e460eb..2326e25 100644
--- a/plc4go/internal/plc4go/knxnetip/readwrite/model/CEMIAdditionalInformation.go
+++ b/plc4go/internal/plc4go/knxnetip/readwrite/model/CEMIAdditionalInformation.go
@@ -146,8 +146,7 @@ func (m *CEMIAdditionalInformation) SerializeParent(writeBuffer utils.WriteBuffe
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/knxnetip/readwrite/model/ComObjectTable.go b/plc4go/internal/plc4go/knxnetip/readwrite/model/ComObjectTable.go
index e002b1f..9c62623 100644
--- a/plc4go/internal/plc4go/knxnetip/readwrite/model/ComObjectTable.go
+++ b/plc4go/internal/plc4go/knxnetip/readwrite/model/ComObjectTable.go
@@ -132,8 +132,7 @@ func (m *ComObjectTable) SerializeParent(writeBuffer utils.WriteBuffer, child IC
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/knxnetip/readwrite/model/ConnectionRequestInformation.go b/plc4go/internal/plc4go/knxnetip/readwrite/model/ConnectionRequestInformation.go
index 94b60d5..23bd71e 100644
--- a/plc4go/internal/plc4go/knxnetip/readwrite/model/ConnectionRequestInformation.go
+++ b/plc4go/internal/plc4go/knxnetip/readwrite/model/ConnectionRequestInformation.go
@@ -163,8 +163,7 @@ func (m *ConnectionRequestInformation) SerializeParent(writeBuffer utils.WriteBu
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/knxnetip/readwrite/model/ConnectionResponseDataBlock.go b/plc4go/internal/plc4go/knxnetip/readwrite/model/ConnectionResponseDataBlock.go
index e1a698e..a40ef6c 100644
--- a/plc4go/internal/plc4go/knxnetip/readwrite/model/ConnectionResponseDataBlock.go
+++ b/plc4go/internal/plc4go/knxnetip/readwrite/model/ConnectionResponseDataBlock.go
@@ -163,8 +163,7 @@ func (m *ConnectionResponseDataBlock) SerializeParent(writeBuffer utils.WriteBuf
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/knxnetip/readwrite/model/KnxGroupAddress.go b/plc4go/internal/plc4go/knxnetip/readwrite/model/KnxGroupAddress.go
index 64a6892..2a626ee 100644
--- a/plc4go/internal/plc4go/knxnetip/readwrite/model/KnxGroupAddress.go
+++ b/plc4go/internal/plc4go/knxnetip/readwrite/model/KnxGroupAddress.go
@@ -132,8 +132,7 @@ func (m *KnxGroupAddress) SerializeParent(writeBuffer utils.WriteBuffer, child I
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/knxnetip/readwrite/model/KnxNetIpMessage.go b/plc4go/internal/plc4go/knxnetip/readwrite/model/KnxNetIpMessage.go
index 4281d6f..2d81de7 100644
--- a/plc4go/internal/plc4go/knxnetip/readwrite/model/KnxNetIpMessage.go
+++ b/plc4go/internal/plc4go/knxnetip/readwrite/model/KnxNetIpMessage.go
@@ -230,8 +230,7 @@ func (m *KnxNetIpMessage) SerializeParent(writeBuffer utils.WriteBuffer, child I
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/knxnetip/readwrite/model/LDataFrame.go b/plc4go/internal/plc4go/knxnetip/readwrite/model/LDataFrame.go
index 100e261..2325b21 100644
--- a/plc4go/internal/plc4go/knxnetip/readwrite/model/LDataFrame.go
+++ b/plc4go/internal/plc4go/knxnetip/readwrite/model/LDataFrame.go
@@ -266,8 +266,7 @@ func (m *LDataFrame) SerializeParent(writeBuffer utils.WriteBuffer, child ILData
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/knxnetip/readwrite/model/ServiceId.go b/plc4go/internal/plc4go/knxnetip/readwrite/model/ServiceId.go
index 45ad575..c1a2c5f 100644
--- a/plc4go/internal/plc4go/knxnetip/readwrite/model/ServiceId.go
+++ b/plc4go/internal/plc4go/knxnetip/readwrite/model/ServiceId.go
@@ -156,8 +156,7 @@ func (m *ServiceId) SerializeParent(writeBuffer utils.WriteBuffer, child IServic
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/modbus/readwrite/model/ModbusPDU.go b/plc4go/internal/plc4go/modbus/readwrite/model/ModbusPDU.go
index d91e046..599d9e8 100644
--- a/plc4go/internal/plc4go/modbus/readwrite/model/ModbusPDU.go
+++ b/plc4go/internal/plc4go/modbus/readwrite/model/ModbusPDU.go
@@ -238,8 +238,7 @@ func (m *ModbusPDU) SerializeParent(writeBuffer utils.WriteBuffer, child IModbus
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/s7/readwrite/model/COTPPacket.go b/plc4go/internal/plc4go/s7/readwrite/model/COTPPacket.go
index 1779373..424d1c6 100644
--- a/plc4go/internal/plc4go/s7/readwrite/model/COTPPacket.go
+++ b/plc4go/internal/plc4go/s7/readwrite/model/COTPPacket.go
@@ -232,8 +232,7 @@ func (m *COTPPacket) SerializeParent(writeBuffer utils.WriteBuffer, child ICOTPP
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/s7/readwrite/model/COTPParameter.go b/plc4go/internal/plc4go/s7/readwrite/model/COTPParameter.go
index ed3be91..998a985 100644
--- a/plc4go/internal/plc4go/s7/readwrite/model/COTPParameter.go
+++ b/plc4go/internal/plc4go/s7/readwrite/model/COTPParameter.go
@@ -169,8 +169,7 @@ func (m *COTPParameter) SerializeParent(writeBuffer utils.WriteBuffer, child ICO
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/s7/readwrite/model/S7Address.go b/plc4go/internal/plc4go/s7/readwrite/model/S7Address.go
index ff41627..ae5962a 100644
--- a/plc4go/internal/plc4go/s7/readwrite/model/S7Address.go
+++ b/plc4go/internal/plc4go/s7/readwrite/model/S7Address.go
@@ -144,8 +144,7 @@ func (m *S7Address) SerializeParent(writeBuffer utils.WriteBuffer, child IS7Addr
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/s7/readwrite/model/S7DataAlarmMessage.go b/plc4go/internal/plc4go/s7/readwrite/model/S7DataAlarmMessage.go
index 8550088..d7bbe4b 100644
--- a/plc4go/internal/plc4go/s7/readwrite/model/S7DataAlarmMessage.go
+++ b/plc4go/internal/plc4go/s7/readwrite/model/S7DataAlarmMessage.go
@@ -171,8 +171,7 @@ func (m *S7DataAlarmMessage) SerializeParent(writeBuffer utils.WriteBuffer, chil
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/s7/readwrite/model/S7Message.go b/plc4go/internal/plc4go/s7/readwrite/model/S7Message.go
index 653907f..d8b65a4 100644
--- a/plc4go/internal/plc4go/s7/readwrite/model/S7Message.go
+++ b/plc4go/internal/plc4go/s7/readwrite/model/S7Message.go
@@ -304,8 +304,7 @@ func (m *S7Message) SerializeParent(writeBuffer utils.WriteBuffer, child IS7Mess
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/s7/readwrite/model/S7Parameter.go b/plc4go/internal/plc4go/s7/readwrite/model/S7Parameter.go
index 3a7f27f..05c64f8 100644
--- a/plc4go/internal/plc4go/s7/readwrite/model/S7Parameter.go
+++ b/plc4go/internal/plc4go/s7/readwrite/model/S7Parameter.go
@@ -157,8 +157,7 @@ func (m *S7Parameter) SerializeParent(writeBuffer utils.WriteBuffer, child IS7Pa
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/s7/readwrite/model/S7ParameterUserDataItem.go b/plc4go/internal/plc4go/s7/readwrite/model/S7ParameterUserDataItem.go
index 4119941..4439b99 100644
--- a/plc4go/internal/plc4go/s7/readwrite/model/S7ParameterUserDataItem.go
+++ b/plc4go/internal/plc4go/s7/readwrite/model/S7ParameterUserDataItem.go
@@ -144,8 +144,7 @@ func (m *S7ParameterUserDataItem) SerializeParent(writeBuffer utils.WriteBuffer,
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/s7/readwrite/model/S7Payload.go b/plc4go/internal/plc4go/s7/readwrite/model/S7Payload.go
index 20648fe..733531f 100644
--- a/plc4go/internal/plc4go/s7/readwrite/model/S7Payload.go
+++ b/plc4go/internal/plc4go/s7/readwrite/model/S7Payload.go
@@ -135,8 +135,7 @@ func (m *S7Payload) SerializeParent(writeBuffer utils.WriteBuffer, child IS7Payl
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/s7/readwrite/model/S7PayloadUserDataItem.go b/plc4go/internal/plc4go/s7/readwrite/model/S7PayloadUserDataItem.go
index 85bacc1..69aca98 100644
--- a/plc4go/internal/plc4go/s7/readwrite/model/S7PayloadUserDataItem.go
+++ b/plc4go/internal/plc4go/s7/readwrite/model/S7PayloadUserDataItem.go
@@ -239,8 +239,7 @@ func (m *S7PayloadUserDataItem) SerializeParent(writeBuffer utils.WriteBuffer, c
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/s7/readwrite/model/S7VarRequestParameterItem.go b/plc4go/internal/plc4go/s7/readwrite/model/S7VarRequestParameterItem.go
index 09e2ba8..5adbed6 100644
--- a/plc4go/internal/plc4go/s7/readwrite/model/S7VarRequestParameterItem.go
+++ b/plc4go/internal/plc4go/s7/readwrite/model/S7VarRequestParameterItem.go
@@ -144,8 +144,7 @@ func (m *S7VarRequestParameterItem) SerializeParent(writeBuffer utils.WriteBuffe
 	}
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
-	_typeSwitchErr := serializeChildFunction()
-	if _typeSwitchErr != nil {
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
 		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
 	}
 
diff --git a/plc4go/internal/plc4go/spi/utils/WriteBuffer.go b/plc4go/internal/plc4go/spi/utils/WriteBuffer.go
index 411d76b..c361f91 100644
--- a/plc4go/internal/plc4go/spi/utils/WriteBuffer.go
+++ b/plc4go/internal/plc4go/spi/utils/WriteBuffer.go
@@ -42,6 +42,7 @@ type WriteBuffer interface {
 	WriteFloat64(logicalName string, bitLength uint8, value float64, writerArgs ...WithWriterArgs) error
 	WriteBigFloat(logicalName string, bitLength uint8, value *big.Float, writerArgs ...WithWriterArgs) error
 	WriteString(logicalName string, bitLength uint32, encoding string, value string, writerArgs ...WithWriterArgs) error
+	WriteVirtual(logicalName string, value interface{}, writerArgs ...WithWriterArgs) error
 	// PopContext signals work done with the context with the supplied logical name
 	PopContext(logicalName string, writerArgs ...WithWriterArgs) error
 }
diff --git a/plc4go/internal/plc4go/spi/utils/WriteBufferBoxBased.go b/plc4go/internal/plc4go/spi/utils/WriteBufferBoxBased.go
index ac1343b..6d16c56 100644
--- a/plc4go/internal/plc4go/spi/utils/WriteBufferBoxBased.go
+++ b/plc4go/internal/plc4go/spi/utils/WriteBufferBoxBased.go
@@ -31,20 +31,18 @@ type WriteBufferBoxBased interface {
 }
 
 func NewBoxedWriteBuffer() WriteBufferBoxBased {
-	return &boxedWriteBuffer{
-		List:         list.New(),
-		desiredWidth: 120,
-		currentWidth: 118,
-	}
+	return NewBoxedWriteBufferWithOptions(false, false)
 }
 
 func NewBoxedWriteBufferWithOptions(mergeSingleBoxes bool, omitEmptyBoxes bool) WriteBufferBoxBased {
 	return &boxedWriteBuffer{
-		List:             list.New(),
-		desiredWidth:     120,
-		currentWidth:     118,
-		mergeSingleBoxes: mergeSingleBoxes,
-		omitEmptyBoxes:   omitEmptyBoxes,
+		List:                list.New(),
+		desiredWidth:        120,
+		currentWidth:        118,
+		mergeSingleBoxes:    mergeSingleBoxes,
+		omitEmptyBoxes:      omitEmptyBoxes,
+		asciiBoxWriter:      AsciiBoxWriterDefault,
+		asciiBoxWriterLight: AsciiBoxWriterLight,
 	}
 }
 
@@ -57,10 +55,12 @@ func NewBoxedWriteBufferWithOptions(mergeSingleBoxes bool, omitEmptyBoxes bool)
 type boxedWriteBuffer struct {
 	bufferCommons
 	*list.List
-	desiredWidth     int
-	currentWidth     int
-	mergeSingleBoxes bool
-	omitEmptyBoxes   bool
+	desiredWidth        int
+	currentWidth        int
+	mergeSingleBoxes    bool
+	omitEmptyBoxes      bool
+	asciiBoxWriter      AsciiBoxWriter
+	asciiBoxWriterLight AsciiBoxWriter
 }
 
 //
@@ -86,13 +86,13 @@ func (b *boxedWriteBuffer) WriteBit(logicalName string, value bool, writerArgs .
 	if value {
 		asInt = 1
 	}
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("b%d %t%s", asInt, value, additionalStringRepresentation), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("b%d %t%s", asInt, value, additionalStringRepresentation), 0))
 	return nil
 }
 
 func (b *boxedWriteBuffer) WriteByte(logicalName string, value byte, writerArgs ...WithWriterArgs) error {
 	additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...)
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("%#02x%s", value, additionalStringRepresentation), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("%#02x%s", value, additionalStringRepresentation), 0))
 	return nil
 }
 
@@ -101,85 +101,113 @@ func (b *boxedWriteBuffer) WriteByteArray(logicalName string, data []byte, write
 	if additionalStringRepresentation != "" {
 		additionalStringRepresentation += "\n"
 	}
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("%s%s", additionalStringRepresentation, Dump(data)), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("%s%s", additionalStringRepresentation, Dump(data)), 0))
 	return nil
 }
 
 func (b *boxedWriteBuffer) WriteUint8(logicalName string, bitLength uint8, value uint8, writerArgs ...WithWriterArgs) error {
 	additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...)
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
 	return nil
 }
 
 func (b *boxedWriteBuffer) WriteUint16(logicalName string, bitLength uint8, value uint16, writerArgs ...WithWriterArgs) error {
 	additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...)
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
 	return nil
 }
 
 func (b *boxedWriteBuffer) WriteUint32(logicalName string, bitLength uint8, value uint32, writerArgs ...WithWriterArgs) error {
 	additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...)
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
 	return nil
 }
 
 func (b *boxedWriteBuffer) WriteUint64(logicalName string, bitLength uint8, value uint64, writerArgs ...WithWriterArgs) error {
 	additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...)
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
 	return nil
 }
 
 func (b *boxedWriteBuffer) WriteInt8(logicalName string, bitLength uint8, value int8, writerArgs ...WithWriterArgs) error {
 	additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...)
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
 	return nil
 }
 
 func (b *boxedWriteBuffer) WriteInt16(logicalName string, bitLength uint8, value int16, writerArgs ...WithWriterArgs) error {
 	additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...)
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
 	return nil
 }
 
 func (b *boxedWriteBuffer) WriteInt32(logicalName string, bitLength uint8, value int32, writerArgs ...WithWriterArgs) error {
 	additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...)
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
 	return nil
 }
 
 func (b *boxedWriteBuffer) WriteInt64(logicalName string, bitLength uint8, value int64, writerArgs ...WithWriterArgs) error {
 	additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...)
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
 	return nil
 }
 
 func (b *boxedWriteBuffer) WriteBigInt(logicalName string, bitLength uint8, value *big.Int, writerArgs ...WithWriterArgs) error {
 	additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...)
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0))
 	return nil
 }
 
 func (b *boxedWriteBuffer) WriteFloat32(logicalName string, bitLength uint8, value float32, writerArgs ...WithWriterArgs) error {
 	additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...)
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %f%s", bitLength/4, value, value, additionalStringRepresentation), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("%#0*x %f%s", bitLength/4, value, value, additionalStringRepresentation), 0))
 	return nil
 }
 
 func (b *boxedWriteBuffer) WriteFloat64(logicalName string, bitLength uint8, value float64, writerArgs ...WithWriterArgs) error {
 	additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...)
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %f%s", bitLength/4, value, value, additionalStringRepresentation), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("%#0*x %f%s", bitLength/4, value, value, additionalStringRepresentation), 0))
 	return nil
 }
 
 func (b *boxedWriteBuffer) WriteBigFloat(logicalName string, bitLength uint8, value *big.Float, writerArgs ...WithWriterArgs) error {
 	additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...)
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %f%s", bitLength/4, value, value, additionalStringRepresentation), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("%#0*x %f%s", bitLength/4, value, value, additionalStringRepresentation), 0))
 	return nil
 }
 
 func (b *boxedWriteBuffer) WriteString(logicalName string, _ uint32, _ string, value string, writerArgs ...WithWriterArgs) error {
 	additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...)
-	b.PushBack(BoxString(logicalName, fmt.Sprintf("%s%s", value, additionalStringRepresentation), 0))
+	b.PushBack(b.asciiBoxWriter.BoxString(logicalName, fmt.Sprintf("%s%s", value, additionalStringRepresentation), 0))
+	return nil
+}
+
+func (b *boxedWriteBuffer) WriteVirtual(logicalName string, value interface{}, writerArgs ...WithWriterArgs) error {
+	additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...)
+	if value == nil {
+		return nil
+	}
+	var asciiBox AsciiBox
+	switch value.(type) {
+	case bool:
+		asciiBox = b.asciiBoxWriterLight.BoxString(logicalName, fmt.Sprintf("%t", value), 0)
+	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
+		asciiBox = b.asciiBoxWriterLight.BoxString(logicalName, fmt.Sprintf("%#x %d%s", value, value, additionalStringRepresentation), 0)
+	case float32, float64:
+		asciiBox = b.asciiBoxWriterLight.BoxString(logicalName, fmt.Sprintf("%x %f%s", value, value, additionalStringRepresentation), 0)
+	case Serializable:
+		virtualBoxedWriteBuffer := NewBoxedWriteBuffer()
+		virtualBoxedWriteBuffer.(*boxedWriteBuffer).asciiBoxWriter = AsciiBoxWriterLight
+		if err := value.(Serializable).Serialize(virtualBoxedWriteBuffer); err == nil {
+			asciiBox = b.asciiBoxWriterLight.BoxBox(logicalName, virtualBoxedWriteBuffer.GetBox(), 0)
+		} else {
+			b.asciiBoxWriterLight.BoxString(logicalName, err.Error(), 0)
+		}
+	default:
+		asciiBox = b.asciiBoxWriterLight.BoxString(logicalName, fmt.Sprintf("%v%s", value, additionalStringRepresentation), 0)
+	}
+	b.PushBack(asciiBox)
 	return nil
 }
 
@@ -214,7 +242,7 @@ findTheBox:
 		b.PushBack(onlyChild)
 		return nil
 	}
-	asciiBox := BoxBox(logicalName, AlignBoxes(finalBoxes, b.currentWidth), 0)
+	asciiBox := b.asciiBoxWriter.BoxBox(logicalName, b.asciiBoxWriter.AlignBoxes(finalBoxes, b.currentWidth), 0)
 	if b.omitEmptyBoxes && asciiBox.IsEmpty() {
 		return nil
 	}
diff --git a/plc4go/internal/plc4go/spi/utils/WriteBufferByteBased.go b/plc4go/internal/plc4go/spi/utils/WriteBufferByteBased.go
index bfe9f11..cbef48c 100644
--- a/plc4go/internal/plc4go/spi/utils/WriteBufferByteBased.go
+++ b/plc4go/internal/plc4go/spi/utils/WriteBufferByteBased.go
@@ -77,10 +77,6 @@ func (wb *byteWriteBuffer) PushContext(_ string, _ ...WithWriterArgs) error {
 	return nil
 }
 
-func (wb *byteWriteBuffer) PopContext(_ string, _ ...WithWriterArgs) error {
-	return nil
-}
-
 func (wb *byteWriteBuffer) SetByteOrder(byteOrder binary.ByteOrder) {
 	wb.byteOrder = byteOrder
 }
@@ -216,3 +212,12 @@ func (wb *byteWriteBuffer) WriteString(_ string, bitLength uint32, encoding stri
 	}
 	return wb.writer.TryError
 }
+
+func (wb *byteWriteBuffer) WriteVirtual(logicalName string, value interface{}, writerArgs ...WithWriterArgs) error {
+	// NO-OP
+	return nil
+}
+
+func (wb *byteWriteBuffer) PopContext(_ string, _ ...WithWriterArgs) error {
+	return nil
+}
diff --git a/plc4go/internal/plc4go/spi/utils/WriteBufferJsonBased.go b/plc4go/internal/plc4go/spi/utils/WriteBufferJsonBased.go
index 3223959..23b9461 100644
--- a/plc4go/internal/plc4go/spi/utils/WriteBufferJsonBased.go
+++ b/plc4go/internal/plc4go/spi/utils/WriteBufferJsonBased.go
@@ -167,6 +167,11 @@ func (j *jsonWriteBuffer) WriteString(logicalName string, bitLength uint32, enco
 	return j.encodeNode(logicalName, value, attr)
 }
 
+func (j *jsonWriteBuffer) WriteVirtual(logicalName string, value interface{}, writerArgs ...WithWriterArgs) error {
+	// NO-OP
+	return nil
+}
+
 func (j *jsonWriteBuffer) PopContext(logicalName string, _ ...WithWriterArgs) error {
 	pop := j.Pop()
 	var poppedName string
diff --git a/plc4go/internal/plc4go/spi/utils/WriteBufferXmlBased.go b/plc4go/internal/plc4go/spi/utils/WriteBufferXmlBased.go
index a73c573..294fc8b 100644
--- a/plc4go/internal/plc4go/spi/utils/WriteBufferXmlBased.go
+++ b/plc4go/internal/plc4go/spi/utils/WriteBufferXmlBased.go
@@ -158,6 +158,11 @@ func (x *xmlWriteBuffer) WriteString(logicalName string, bitLength uint32, encod
 	return x.encodeElement(logicalName, value, attr, writerArgs...)
 }
 
+func (x *xmlWriteBuffer) WriteVirtual(logicalName string, value interface{}, writerArgs ...WithWriterArgs) error {
+	// NO-OP
+	return nil
+}
+
 func (x *xmlWriteBuffer) PopContext(logicalName string, _ ...WithWriterArgs) error {
 	if err := x.Encoder.EncodeToken(xml.EndElement{Name: xml.Name{Local: x.sanitizeLogicalName(logicalName)}}); err != nil {
 		return err
diff --git a/plc4go/internal/plc4go/spi/utils/asciiBox.go b/plc4go/internal/plc4go/spi/utils/asciiBox.go
index 34fa733..b82fa9d 100644
--- a/plc4go/internal/plc4go/spi/utils/asciiBox.go
+++ b/plc4go/internal/plc4go/spi/utils/asciiBox.go
@@ -27,7 +27,10 @@ import (
 )
 
 // AsciiBox is a string surrounded by an ascii border (and an optional name)
-type AsciiBox string
+type AsciiBox struct {
+	data           string
+	asciiBoxWriter *asciiBoxWriter
+}
 
 // DebugAsciiBox set to true to get debug messages
 var DebugAsciiBox bool
@@ -38,6 +41,205 @@ type AsciiBoxer interface {
 	Box(string, int) AsciiBox
 }
 
+var AsciiBoxWriterDefault = NewAsciiBoxWriter()
+
+var AsciiBoxWriterLight = NewAsciiBoxWriterWithCustomBorders(
+	"╭",
+	"╮",
+	"┄",
+	"┆",
+	"╰",
+	"╯",
+)
+
+type AsciiBoxWriter interface {
+	BoxBox(name string, box AsciiBox, charWidth int) AsciiBox
+	BoxString(name string, data string, charWidth int) AsciiBox
+	AlignBoxes(asciiBoxes []AsciiBox, desiredWith int) AsciiBox
+	BoxSideBySide(box1 AsciiBox, box2 AsciiBox) AsciiBox
+	BoxBelowBox(box1 AsciiBox, box2 AsciiBox) AsciiBox
+}
+
+func NewAsciiBoxWriter() AsciiBoxWriter {
+	return NewAsciiBoxWriterWithCustomBorders(
+		"╔",
+		"╗",
+		"═",
+		"║",
+		"╚",
+		"╝",
+	)
+}
+
+func NewAsciiBoxWriterWithCustomBorders(upperLeftCorner string, upperRightCorner string, horizontalLine string, verticalLine string, lowerLeftCorner string, lowerRightCorner string) AsciiBoxWriter {
+	return &asciiBoxWriter{
+		upperLeftCorner:  upperLeftCorner,
+		upperRightCorner: upperRightCorner,
+		horizontalLine:   horizontalLine,
+		verticalLine:     verticalLine,
+		lowerLeftCorner:  lowerLeftCorner,
+		lowerRightCorner: lowerRightCorner,
+		newLine:          '\n',
+		emptyPadding:     " ",
+		// the name gets prefixed with a extra symbol for indent
+		extraNameCharIndent: 1,
+		borderWidth:         1,
+		newLineCharWidth:    1,
+		boxNameRegex:        regexp.MustCompile(`^` + upperLeftCorner + horizontalLine + `(?P<name>[\w /]+)` + horizontalLine + `*` + upperRightCorner),
+	}
+}
+
+///////////////////////////////////////
+///////////////////////////////////////
+//
+// Internal section
+//
+
+type asciiBoxWriter struct {
+	upperLeftCorner  string
+	upperRightCorner string
+	horizontalLine   string
+	verticalLine     string
+	lowerLeftCorner  string
+	lowerRightCorner string
+	newLine          rune
+	emptyPadding     string
+	// the name gets prefixed with a extra symbol for indent
+	extraNameCharIndent int
+	borderWidth         int
+	newLineCharWidth    int
+	boxNameRegex        *regexp.Regexp
+}
+
+func (a *asciiBoxWriter) boxString(name string, data string, charWidth int) AsciiBox {
+	rawBox := AsciiBox{data, a}
+	longestLine := rawBox.Width()
+	if charWidth < longestLine {
+		if DebugAsciiBox {
+			log.Debug().Msgf("Overflow by %d chars", longestLine-charWidth)
+		}
+		charWidth = longestLine + a.borderWidth + a.borderWidth
+	}
+	var boxedString strings.Builder
+	boxedString.Grow((a.borderWidth + longestLine + a.borderWidth + a.newLineCharWidth) * rawBox.Height())
+	namePadding := int(math.Max(float64(charWidth-countChars(name)-a.borderWidth-a.extraNameCharIndent-a.borderWidth), 0))
+	boxedString.WriteString(a.upperLeftCorner + a.horizontalLine + name + strings.Repeat(a.horizontalLine, namePadding) + a.upperRightCorner)
+	boxedString.WriteRune(a.newLine)
+	// Name of the header stretches the box so we align to that
+	charWidth = a.borderWidth + a.extraNameCharIndent + countChars(name) + namePadding + a.borderWidth
+	for _, line := range rawBox.Lines() {
+		linePadding := float64(charWidth - boxLineOverheat - countChars(line))
+		if linePadding < 0 {
+			linePadding = 0
+		}
+		frontPadding := math.Floor(linePadding / 2.0)
+		backPadding := math.Ceil(linePadding / 2.0)
+		boxedString.WriteString(a.verticalLine + strings.Repeat(a.emptyPadding, int(frontPadding)) + line + strings.Repeat(a.emptyPadding, int(backPadding)) + a.verticalLine)
+		boxedString.WriteRune(a.newLine)
+	}
+	bottomPadding := namePadding + countChars(name) + a.extraNameCharIndent
+	boxedString.WriteString(a.lowerLeftCorner + strings.Repeat(a.horizontalLine, bottomPadding) + a.lowerRightCorner)
+	return AsciiBox{boxedString.String(), a}
+}
+
+func (a *asciiBoxWriter) getBoxName(box AsciiBox) string {
+	subMatch := a.boxNameRegex.FindStringSubmatch(box.String())
+	if subMatch == nil {
+		return ""
+	}
+	if len(subMatch) != 2 {
+		panic("should never occur as we only have one named group")
+	}
+	return subMatch[1]
+}
+
+func (a *asciiBoxWriter) changeBoxName(box AsciiBox, newName string) AsciiBox {
+	if !a.hasBorders(box) {
+		return a.boxString(newName, box.String(), 0)
+	}
+	minimumWidthWithNewName := countChars(a.upperLeftCorner + a.horizontalLine + newName + a.upperRightCorner)
+	nameLengthDifference := minimumWidthWithNewName - (a.unwrap(box).Width() + a.borderWidth + a.borderWidth)
+	return a.BoxString(newName, a.unwrap(box).String(), box.Width()+nameLengthDifference)
+}
+
+func (a *asciiBoxWriter) mergeHorizontal(boxes []AsciiBox) AsciiBox {
+	switch len(boxes) {
+	case 0:
+		return AsciiBox{"", a}
+	case 1:
+		return boxes[0]
+	case 2:
+		return a.BoxSideBySide(boxes[0], boxes[1])
+	default:
+		return a.BoxSideBySide(boxes[0], a.mergeHorizontal(boxes[1:]))
+	}
+}
+
+func (a *asciiBoxWriter) expandBox(box AsciiBox, desiredWidth int) AsciiBox {
+	if box.Width() >= desiredWidth {
+		return box
+	}
+	boxLines := box.Lines()
+	numberOfLine := len(boxLines)
+	boxWidth := box.Width()
+	padding := strings.Repeat(" ", desiredWidth-boxWidth)
+	var newBox strings.Builder
+	newBox.Grow((boxWidth + a.newLineCharWidth) * numberOfLine)
+	for i, line := range boxLines {
+		newBox.WriteString(line)
+		newBox.WriteString(padding)
+		if i < numberOfLine-1 {
+			newBox.WriteRune(a.newLine)
+		}
+	}
+	return AsciiBox{newBox.String(), a}
+}
+
+func (a *asciiBoxWriter) unwrap(box AsciiBox) AsciiBox {
+	if !a.hasBorders(box) {
+		return box
+	}
+	originalLines := box.Lines()
+	newLines := make([]string, len(originalLines)-2)
+	for i, line := range originalLines {
+		if i == 0 {
+			// we ignore the first line
+			continue
+		}
+		if i == len(originalLines)-1 {
+			// we ignore the last line
+			break
+		}
+		runes := []rune(line)
+		// Strip the vertical Lines and trim the padding
+		unwrappedLine := string(runes[1 : len(runes)-1])
+		if !strings.ContainsAny(unwrappedLine, a.verticalLine+a.horizontalLine) {
+			// only trim boxes witch don't contain other boxes
+			unwrappedLine = strings.Trim(unwrappedLine, a.emptyPadding)
+		}
+		newLines[i-1] = unwrappedLine
+	}
+	return AsciiBox{strings.Join(newLines, string(a.newLine)), a}
+}
+
+func (a *asciiBoxWriter) hasBorders(box AsciiBox) bool {
+	if len(box.String()) == 0 {
+		return false
+	}
+	// Check if the first char is the upper left corner
+	return []rune(box.String())[0] == []rune(a.upperLeftCorner)[0]
+}
+
+func countChars(s string) int {
+	return len([]rune(s))
+}
+
+//
+// Internal section
+//
+///////////////////////////////////////
+///////////////////////////////////////
+
 // Width returns the width of the box without the newlines
 func (m AsciiBox) Width() int {
 	maxWidth := 0
@@ -57,43 +259,43 @@ func (m AsciiBox) Height() int {
 
 // Lines returns the lines of the box
 func (m AsciiBox) Lines() []string {
-	return strings.Split(string(m), "\n")
+	return strings.Split(m.data, "\n")
 }
 
 func (m AsciiBox) GetBoxName() string {
-	return getBoxName(m)
+	return m.asciiBoxWriter.getBoxName(m)
 }
 
 func (m AsciiBox) ChangeBoxName(newName string) AsciiBox {
-	return changeBoxName(m, newName)
+	return m.asciiBoxWriter.changeBoxName(m, newName)
 }
 
 func (m AsciiBox) IsEmpty() bool {
-	if hasBorders(m) {
-		return unwrap(m).String() == ""
+	if m.asciiBoxWriter.hasBorders(m) {
+		return m.asciiBoxWriter.unwrap(m).String() == ""
 	}
 	return m.String() == ""
 }
 
 // String returns the string of the box
 func (m AsciiBox) String() string {
-	return string(m)
+	return m.data
 }
 
 // BoxBox boxes a box
-func BoxBox(name string, box AsciiBox, charWidth int) AsciiBox {
-	return BoxString(name, string(box), charWidth)
+func (a *asciiBoxWriter) BoxBox(name string, box AsciiBox, charWidth int) AsciiBox {
+	return a.BoxString(name, box.data, charWidth)
 }
 
 // BoxString boxes a newline separated string into a beautiful box
-func BoxString(name string, data string, charWidth int) AsciiBox {
-	return boxString(name, data, charWidth)
+func (a *asciiBoxWriter) BoxString(name string, data string, charWidth int) AsciiBox {
+	return a.boxString(name, data, charWidth)
 }
 
 // AlignBoxes aligns all boxes to a desiredWidth and orders them from left to right and top to bottom (size will be at min the size of the biggest box)
-func AlignBoxes(boxes []AsciiBox, desiredWidth int) AsciiBox {
+func (a *asciiBoxWriter) AlignBoxes(boxes []AsciiBox, desiredWidth int) AsciiBox {
 	if len(boxes) == 0 {
-		return ""
+		return AsciiBox{"", a}
 	}
 	actualWidth := desiredWidth
 	for _, box := range boxes {
@@ -108,17 +310,17 @@ func AlignBoxes(boxes []AsciiBox, desiredWidth int) AsciiBox {
 	if DebugAsciiBox {
 		log.Debug().Msgf("Working with %d chars", actualWidth)
 	}
-	bigBox := AsciiBox("")
+	bigBox := AsciiBox{"", a}
 	currentBoxRow := make([]AsciiBox, 0)
 	currentRowLength := 0
 	for _, box := range boxes {
 		currentRowLength += box.Width()
 		if currentRowLength > actualWidth {
-			mergedBoxes := mergeHorizontal(currentBoxRow)
-			if bigBox == "" {
+			mergedBoxes := a.mergeHorizontal(currentBoxRow)
+			if bigBox.IsEmpty() {
 				bigBox = mergedBoxes
 			} else {
-				bigBox = BoxBelowBox(bigBox, mergedBoxes)
+				bigBox = a.BoxBelowBox(bigBox, mergedBoxes)
 			}
 			currentRowLength = box.Width()
 			currentBoxRow = make([]AsciiBox, 0)
@@ -127,18 +329,18 @@ func AlignBoxes(boxes []AsciiBox, desiredWidth int) AsciiBox {
 	}
 	if len(currentBoxRow) > 0 {
 		// Special case where all boxes fit into one row
-		mergedBoxes := mergeHorizontal(currentBoxRow)
-		if bigBox == "" {
+		mergedBoxes := a.mergeHorizontal(currentBoxRow)
+		if bigBox.IsEmpty() {
 			bigBox = mergedBoxes
 		} else {
-			bigBox = BoxBelowBox(bigBox, mergedBoxes)
+			bigBox = a.BoxBelowBox(bigBox, mergedBoxes)
 		}
 	}
 	return bigBox
 }
 
 // BoxSideBySide renders two boxes side by side
-func BoxSideBySide(box1, box2 AsciiBox) AsciiBox {
+func (a *asciiBoxWriter) BoxSideBySide(box1, box2 AsciiBox) AsciiBox {
 	const newLineCharWidth = 1
 	var aggregateBox strings.Builder
 	box1Width := box1.Width()
@@ -172,173 +374,17 @@ func BoxSideBySide(box1, box2 AsciiBox) AsciiBox {
 			aggregateBox.WriteRune('\n')
 		}
 	}
-	return AsciiBox(aggregateBox.String())
+	return AsciiBox{aggregateBox.String(), a}
 }
 
 // BoxBelowBox renders two boxes below
-func BoxBelowBox(box1, box2 AsciiBox) AsciiBox {
+func (a *asciiBoxWriter) BoxBelowBox(box1, box2 AsciiBox) AsciiBox {
 	box1Width := box1.Width()
 	box2Width := box2.Width()
 	if box1Width < box2Width {
-		box1 = expandBox(box1, box2Width)
+		box1 = a.expandBox(box1, box2Width)
 	} else if box2Width < box1Width {
-		box2 = expandBox(box2, box1Width)
-	}
-	return AsciiBox(box1.String() + "\n" + box2.String())
-}
-
-///////////////////////////////////////
-///////////////////////////////////////
-//
-// Internal section
-//
-
-const (
-	upperLeftCorner  = "╔"
-	upperRightCorner = "╗"
-	horizontalLine   = "═"
-	verticalLine     = "║"
-	lowerLeftCorner  = "╚"
-	lowerRightCorner = "╝"
-	newLine          = '\n'
-	emptyPadding     = " "
-	// the name gets prefixed with a extra symbol for indent
-	extraNameCharIndent = 1
-	borderWidth         = 1
-	newLineCharWidth    = 1
-)
-
-var boxNameRegex *regexp.Regexp
-
-func init() {
-	boxNameRegex = regexp.MustCompile(`^` + upperLeftCorner + horizontalLine + `(?P<name>[\w /]+)` + horizontalLine + `*` + upperRightCorner)
-}
-
-func boxString(name string, data string, charWidth int) AsciiBox {
-	rawBox := AsciiBox(data)
-	longestLine := rawBox.Width()
-	if charWidth < longestLine {
-		if DebugAsciiBox {
-			log.Debug().Msgf("Overflow by %d chars", longestLine-charWidth)
-		}
-		charWidth = longestLine + borderWidth + borderWidth
-	}
-	var boxedString strings.Builder
-	boxedString.Grow((borderWidth + longestLine + borderWidth + newLineCharWidth) * rawBox.Height())
-	namePadding := int(math.Max(float64(charWidth-countChars(name)-borderWidth-extraNameCharIndent-borderWidth), 0))
-	boxedString.WriteString(upperLeftCorner + horizontalLine + name + strings.Repeat(horizontalLine, namePadding) + upperRightCorner)
-	boxedString.WriteRune(newLine)
-	// Name of the header stretches the box so we align to that
-	charWidth = borderWidth + extraNameCharIndent + countChars(name) + namePadding + borderWidth
-	for _, line := range rawBox.Lines() {
-		linePadding := float64(charWidth - boxLineOverheat - countChars(line))
-		if linePadding < 0 {
-			linePadding = 0
-		}
-		frontPadding := math.Floor(linePadding / 2.0)
-		backPadding := math.Ceil(linePadding / 2.0)
-		boxedString.WriteString(verticalLine + strings.Repeat(emptyPadding, int(frontPadding)) + line + strings.Repeat(emptyPadding, int(backPadding)) + verticalLine)
-		boxedString.WriteRune(newLine)
-	}
-	bottomPadding := namePadding + countChars(name) + extraNameCharIndent
-	boxedString.WriteString(lowerLeftCorner + strings.Repeat(horizontalLine, bottomPadding) + lowerRightCorner)
-	return AsciiBox(boxedString.String())
-}
-
-func getBoxName(box AsciiBox) string {
-	subMatch := boxNameRegex.FindStringSubmatch(box.String())
-	if subMatch == nil {
-		return ""
-	}
-	if len(subMatch) != 2 {
-		panic("should never occur as we only have one named group")
-	}
-	return subMatch[1]
-}
-
-func changeBoxName(box AsciiBox, newName string) AsciiBox {
-	if !hasBorders(box) {
-		return boxString(newName, box.String(), 0)
-	}
-	minimumWidthWithNewName := countChars(upperLeftCorner + horizontalLine + newName + upperRightCorner)
-	nameLengthDifference := minimumWidthWithNewName - (unwrap(box).Width() + borderWidth + borderWidth)
-	return BoxString(newName, unwrap(box).String(), box.Width()+nameLengthDifference)
-}
-
-func mergeHorizontal(boxes []AsciiBox) AsciiBox {
-	switch len(boxes) {
-	case 0:
-		return ""
-	case 1:
-		return boxes[0]
-	case 2:
-		return BoxSideBySide(boxes[0], boxes[1])
-	default:
-		return BoxSideBySide(boxes[0], mergeHorizontal(boxes[1:]))
-	}
-}
-
-func expandBox(box AsciiBox, desiredWidth int) AsciiBox {
-	if box.Width() >= desiredWidth {
-		return box
-	}
-	boxLines := box.Lines()
-	numberOfLine := len(boxLines)
-	boxWidth := box.Width()
-	padding := strings.Repeat(" ", desiredWidth-boxWidth)
-	var newBox strings.Builder
-	newBox.Grow((boxWidth + newLineCharWidth) * numberOfLine)
-	for i, line := range boxLines {
-		newBox.WriteString(line)
-		newBox.WriteString(padding)
-		if i < numberOfLine-1 {
-			newBox.WriteRune(newLine)
-		}
+		box2 = a.expandBox(box2, box1Width)
 	}
-	return AsciiBox(newBox.String())
+	return AsciiBox{box1.String() + "\n" + box2.String(), a}
 }
-
-func unwrap(box AsciiBox) AsciiBox {
-	if !hasBorders(box) {
-		return box
-	}
-	originalLines := box.Lines()
-	newLines := make([]string, len(originalLines)-2)
-	for i, line := range originalLines {
-		if i == 0 {
-			// we ignore the first line
-			continue
-		}
-		if i == len(originalLines)-1 {
-			// we ignore the last line
-			break
-		}
-		runes := []rune(line)
-		// Strip the vertical Lines and trim the padding
-		unwrappedLine := string(runes[1 : len(runes)-1])
-		if !strings.ContainsAny(unwrappedLine, verticalLine+horizontalLine) {
-			// only trim boxes witch don't contain other boxes
-			unwrappedLine = strings.Trim(unwrappedLine, emptyPadding)
-		}
-		newLines[i-1] = unwrappedLine
-	}
-	return AsciiBox(strings.Join(newLines, string(newLine)))
-}
-
-func hasBorders(box AsciiBox) bool {
-	if len(box.String()) == 0 {
-		return false
-	}
-	// Check if the first char is the upper left corner
-	return []rune(box.String())[0] == []rune(upperLeftCorner)[0]
-}
-
-func countChars(s string) int {
-	return len([]rune(s))
-}
-
-//
-// Internal section
-//
-///////////////////////////////////////
-///////////////////////////////////////
diff --git a/plc4go/internal/plc4go/spi/utils/asciiBox_test.go b/plc4go/internal/plc4go/spi/utils/asciiBox_test.go
index e1e28ee..13ccf8f 100644
--- a/plc4go/internal/plc4go/spi/utils/asciiBox_test.go
+++ b/plc4go/internal/plc4go/spi/utils/asciiBox_test.go
@@ -41,28 +41,28 @@ func TestAsciiBox_GetBoxName(t *testing.T) {
 		{
 			name: "simple name",
 			args: args{
-				box: BoxString("someName", "some content", 0),
+				box: AsciiBoxWriterDefault.BoxString("someName", "some content", 0),
 			},
 			want: "someName",
 		},
 		{
 			name: "no name",
 			args: args{
-				box: BoxString("", "some content", 0),
+				box: AsciiBoxWriterDefault.BoxString("", "some content", 0),
 			},
 			want: "",
 		},
 		{
 			name: "long name",
 			args: args{
-				box: BoxString("veryLongName12_13", "some content", 0),
+				box: AsciiBoxWriterDefault.BoxString("veryLongName12_13", "some content", 0),
 			},
 			want: "veryLongName12_13",
 		},
 		{
 			name: "name with spaces and slashes",
 			args: args{
-				box: BoxString("payload / Message / Concrete Message", "some content", 0),
+				box: AsciiBoxWriterDefault.BoxString("payload / Message / Concrete Message", "some content", 0),
 			},
 			want: "payload / Message / Concrete Message",
 		},
@@ -89,26 +89,26 @@ func TestAsciiBox_ChangeBoxName(t *testing.T) {
 		{
 			name: "box with simple name",
 			args: args{
-				box:     BoxString("simpleName", "some content", 0),
+				box:     AsciiBoxWriterDefault.BoxString("simpleName", "some content", 0),
 				newName: "newSimpleName",
 			},
-			want: BoxString("newSimpleName", "some content", 0),
+			want: AsciiBoxWriterDefault.BoxString("newSimpleName", "some content", 0),
 		},
 		{
 			name: "box with shorter name",
 			args: args{
-				box:     BoxString("veryLongName", "some content", 0),
+				box:     AsciiBoxWriterDefault.BoxString("veryLongName", "some content", 0),
 				newName: "name",
 			},
-			want: BoxString("name", "some content", 0),
+			want: AsciiBoxWriterDefault.BoxString("name", "some content", 0),
 		},
 		{
 			name: "box getting dressed",
 			args: args{
-				box:     `some content`,
+				box:     asciiBox("some content"),
 				newName: "name",
 			},
-			want: BoxString("name", "some content", 0),
+			want: AsciiBoxWriterDefault.BoxString("name", "some content", 0),
 		},
 	}
 	for _, tt := range tests {
@@ -133,28 +133,28 @@ func TestAsciiBox_IsEmpty(t *testing.T) {
 		{
 			name: "empty box",
 			args: args{
-				box: "",
+				box: asciiBox(""),
 			},
 			want: true,
 		},
 		{
 			name: "non empty box",
 			args: args{
-				box: "a",
+				box: asciiBox("a"),
 			},
 			want: false,
 		},
 		{
 			name: "name empty box",
 			args: args{
-				box: BoxString("name", "", 0),
+				box: AsciiBoxWriterDefault.BoxString("name", "", 0),
 			},
 			want: true,
 		},
 		{
 			name: "name non empty box",
 			args: args{
-				box: BoxString("name", "a", 0),
+				box: AsciiBoxWriterDefault.BoxString("name", "a", 0),
 			},
 			want: false,
 		},
@@ -181,14 +181,14 @@ func TestBoxSideBySide(t *testing.T) {
 		{
 			name: "Test2Boxes",
 			args: args{
-				box1: `
+				box1: asciiBox(`
 000 0x: 31  32  33  34  35  36  37  38  '12345678'
 008 0x: 39  30  61  62  63  64  65  66  '90abcdef'
 016 0x: 67  68  69  6a  6b  6c  6d  6e  'ghijklmn'
 024 0x: 6f  70  71  72  73  74  75  76  'opqrstuv'
 032 0x: 77  78  79  7a                  'wxyz    '
-`,
-				box2: `
+`),
+				box2: asciiBox(`
 ╔═super nice data══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
 ║  000 0x: 31  32  33  34  35  36  37  38  39  30  61  62  63  64  65  66  67  68  69  6a  6b  6c  6d  6e  '1234567890abcdefghijklmn'  ║
 ║  024 0x: 6f  70  71  72  73  74  75  76  77  78  79  7a  d3  31  32  33  34  35  36  37  38  39  30  61  'opqrstuvwxyz.1234567890a'  ║
@@ -198,9 +198,9 @@ func TestBoxSideBySide(t *testing.T) {
 ║  120 0x: 38  39  30  61  62  63  64  65  66  67  68  69  6a  6b  6c  6d  6e  6f  70  71  72  73  74  75  '890abcdefghijklmnopqrstu'  ║
 ║  144 0x: 76  77  78  79  7a  d3  61  61  62                                                              'vwxyz.aab               '  ║
 ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
-`,
+`),
 			},
-			want: `
+			want: asciiBox(`
 000 0x: 31  32  33  34  35  36  37  38  '12345678'╔═super nice data══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
 008 0x: 39  30  61  62  63  64  65  66  '90abcdef'║  000 0x: 31  32  33  34  35  36  37  38  39  30  61  62  63  64  65  66  67  68  69  6a  6b  6c  6d  6e  '1234567890abcdefghijklmn'  ║
 016 0x: 67  68  69  6a  6b  6c  6d  6e  'ghijklmn'║  024 0x: 6f  70  71  72  73  74  75  76  77  78  79  7a  d3  31  32  33  34  35  36  37  38  39  30  61  'opqrstuvwxyz.1234567890a'  ║
@@ -210,77 +210,77 @@ func TestBoxSideBySide(t *testing.T) {
                                                   ║  120 0x: 38  39  30  61  62  63  64  65  66  67  68  69  6a  6b  6c  6d  6e  6f  70  71  72  73  74  75  '890abcdefghijklmnopqrstu'  ║
                                                   ║  144 0x: 76  77  78  79  7a  d3  61  61  62                                                              'vwxyz.aab               '  ║
                                                   ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
-`,
+`),
 		},
 		{
 			name: "another 2 boxes",
 			args: args{
-				box1: `
+				box1: asciiBox(`
 ╔═exampleInt╗
 ║     4     ║
 ╚═══════════╝
-`,
-				box2: `
+`),
+				box2: asciiBox(`
 ╔═exampleInt╗
 ║     7     ║
 ╚═══════════╝
-`,
+`),
 			},
-			want: `
+			want: asciiBox(`
 ╔═exampleInt╗╔═exampleInt╗
 ║     4     ║║     7     ║
 ╚═══════════╝╚═══════════╝
-`,
+`),
 		},
 		{
 			name: "size difference first box",
 			args: args{
-				box1: `
+				box1: asciiBox(`
 ╔═exampleInt╗
 ║     4     ║
 ║     4     ║
 ╚═══════════╝
-`,
-				box2: `
+`),
+				box2: asciiBox(`
 ╔═exampleInt╗
 ║     7     ║
 ╚═══════════╝
-`,
+`),
 			},
-			want: `
+			want: asciiBox(`
 ╔═exampleInt╗╔═exampleInt╗
 ║     4     ║║     7     ║
 ║     4     ║╚═══════════╝
 ╚═══════════╝             
-`,
+`),
 		},
 		{
 			name: "size difference second box",
 			args: args{
-				box1: `
+				box1: asciiBox(`
 ╔═exampleInt╗
 ║     4     ║
 ╚═══════════╝
-`,
-				box2: `
+`),
+				box2: asciiBox(`
 ╔═exampleInt╗
 ║     7     ║
 ║     7     ║
 ╚═══════════╝
-`,
+`),
 			},
-			want: `
+			want: asciiBox(`
 ╔═exampleInt╗╔═exampleInt╗
 ║     4     ║║     7     ║
 ╚═══════════╝║     7     ║
              ╚═══════════╝
-`,
+`),
 		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			tt.want = trimBox(tt.want)
-			if got := BoxSideBySide(trimBox(tt.args.box1), trimBox(tt.args.box2)); got != tt.want {
+			if got := AsciiBoxWriterDefault.BoxSideBySide(trimBox(tt.args.box1), trimBox(tt.args.box2)); got != tt.want {
 				t.Errorf("BoxSideBySide() = '\n%v\n', want '\n%v\n'", got, tt.want)
 			}
 		})
@@ -291,10 +291,10 @@ func BenchmarkBoxSideBySide(b *testing.B) {
 	oldSetting := DebugAsciiBox
 	DebugAsciiBox = false
 	bigString := strings.Repeat(strings.Repeat("LoreIpsum", 100)+"\n", 100)
-	box := BoxString("RandomBox", bigString, 100)
+	box := AsciiBoxWriterDefault.BoxString("RandomBox", bigString, 100)
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
-		BoxSideBySide(box, box)
+		AsciiBoxWriterDefault.BoxSideBySide(box, box)
 	}
 	DebugAsciiBox = oldSetting
 }
@@ -312,14 +312,14 @@ func TestBoxBelowBox(t *testing.T) {
 		{
 			name: "Test2Boxes",
 			args: args{
-				box1: `
+				box1: asciiBox(`
 000 31  32  33  34  35  36  37  38  '12345678'
 008 39  30  61  62  63  64  65  66  '90abcdef'
 016 67  68  69  6a  6b  6c  6d  6e  'ghijklmn'
 024 6f  70  71  72  73  74  75  76  'opqrstuv'
 032 77  78  79  7a                  'wxyz    '
-`,
-				box2: `
+`),
+				box2: asciiBox(`
 ╔═super nice data══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
 ║  000 31  32  33  34  35  36  37  38  39  30  61  62  63  64  65  66  67  68  69  6a  6b  6c  6d  6e  '1234567890abcdefghijklmn'  ║
 ║  024 6f  70  71  72  73  74  75  76  77  78  79  7a  d3  31  32  33  34  35  36  37  38  39  30  61  'opqrstuvwxyz.1234567890a'  ║
@@ -329,9 +329,9 @@ func TestBoxBelowBox(t *testing.T) {
 ║  120 38  39  30  61  62  63  64  65  66  67  68  69  6a  6b  6c  6d  6e  6f  70  71  72  73  74  75  '890abcdefghijklmnopqrstu'  ║
 ║  144 76  77  78  79  7a  d3  61  61  62                                                              'vwxyz.aab               '  ║
 ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
-`,
+`),
 			},
-			want: `
+			want: asciiBox(`
 000 31  32  33  34  35  36  37  38  '12345678'                                                                                      
 008 39  30  61  62  63  64  65  66  '90abcdef'                                                                                      
 016 67  68  69  6a  6b  6c  6d  6e  'ghijklmn'                                                                                      
@@ -345,36 +345,37 @@ func TestBoxBelowBox(t *testing.T) {
 ║  096 6b  6c  6d  6e  6f  70  71  72  73  74  75  76  77  78  79  7a  d3  31  32  33  34  35  36  37  'klmnopqrstuvwxyz.1234567'  ║
 ║  120 38  39  30  61  62  63  64  65  66  67  68  69  6a  6b  6c  6d  6e  6f  70  71  72  73  74  75  '890abcdefghijklmnopqrstu'  ║
 ║  144 76  77  78  79  7a  d3  61  61  62                                                              'vwxyz.aab               '  ║
-╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝`,
+╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
+`),
 		},
 		{
 			name: "different sized boxes",
 			args: args{
-				box1: `
+				box1: asciiBox(`
 ╔═sampleField════════════╗
 ║123123123123123123123123║
 ╚════════════════════════╝
-`,
-				box2: `
+`),
+				box2: asciiBox(`
 ╔═sampleField╗
 ║123123123123║
 ╚════════════╝
-`,
+`),
 			},
-			want: `
+			want: asciiBox(`
 ╔═sampleField════════════╗
 ║123123123123123123123123║
 ╚════════════════════════╝
 ╔═sampleField╗            
 ║123123123123║            
 ╚════════════╝            
-`,
+`),
 		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			tt.want = trimBox(tt.want)
-			if got := BoxBelowBox(trimBox(tt.args.box1), trimBox(tt.args.box2)); got != tt.want {
+			if got := AsciiBoxWriterDefault.BoxBelowBox(trimBox(tt.args.box1), trimBox(tt.args.box2)); got != tt.want {
 				t.Errorf("BoxSideBySide() = '\n%v\n', want '\n%v\n'", got, tt.want)
 			}
 		})
@@ -399,11 +400,11 @@ func TestBoxString(t *testing.T) {
 				data:      "123123123123",
 				charWidth: 1,
 			},
-			want: `
+			want: asciiBox(`
 ╔═sampleField╗
 ║123123123123║
 ╚════════════╝
-`,
+`),
 		},
 		{
 			name: "simplebox-unamed",
@@ -412,11 +413,11 @@ func TestBoxString(t *testing.T) {
 				data:      "123123123123",
 				charWidth: 1,
 			},
-			want: `
+			want: asciiBox(`
 ╔════════════╗
 ║123123123123║
 ╚════════════╝
-`,
+`),
 		},
 		{
 			name: "simplebox 2",
@@ -425,12 +426,12 @@ func TestBoxString(t *testing.T) {
 				data:      "123123123123\n123123123123123123123123",
 				charWidth: 1,
 			},
-			want: `
+			want: asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123123123123123123123║
 ╚════════════════════════╝
-`,
+`),
 		},
 		{
 			name: "simplebox with too long name",
@@ -439,18 +440,18 @@ func TestBoxString(t *testing.T) {
 				data:      "123123123123\n123123123123123123123123",
 				charWidth: 1,
 			},
-			want: `
+			want: asciiBox(`
 ╔═sampleFieldsampleFieldsampleFieldsampleField╗
 ║                123123123123                 ║
 ║          123123123123123123123123           ║
 ╚═════════════════════════════════════════════╝
-`,
+`),
 		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			tt.want = trimBox(tt.want)
-			if got := BoxString(tt.args.name, tt.args.data, tt.args.charWidth); got != tt.want {
+			if got := AsciiBoxWriterDefault.BoxString(tt.args.name, tt.args.data, tt.args.charWidth); got != tt.want {
 				t.Errorf("BoxString() = '\n%v\n', want '\n%v\n'", got, tt.want)
 			}
 		})
@@ -463,7 +464,7 @@ func BenchmarkBoxString(b *testing.B) {
 	bigString := strings.Repeat(strings.Repeat("LoreIpsum", 100)+"\n", 100)
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
-		BoxString("randomName", bigString, 50)
+		AsciiBoxWriterDefault.BoxString("randomName", bigString, 50)
 	}
 	DebugAsciiBox = oldSetting
 }
@@ -482,48 +483,48 @@ func TestAlignBoxes(t *testing.T) {
 			name: "enough space",
 			args: args{
 				boxes: []AsciiBox{
-					`
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123ABABABABABAB123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123123123123123123123║
 ╚════════════════════════╝
-`,
+`),
 				},
 				desiredWith: 1000,
 			},
-			want: `
+			want: asciiBox(`
 ╔═sampleField════════════╗╔═sampleField════════════╗
 ║      123123123123      ║║      123123123123      ║
 ║123123ABABABABABAB123123║║123123123123123123123123║
 ╚════════════════════════╝╚════════════════════════╝
-`,
+`),
 		},
 		{
 			name: "not enough space",
 			args: args{
 				boxes: []AsciiBox{
-					`
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123ABABABABABAB123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123123123123123123123║
 ╚════════════════════════╝
-`,
+`),
 				},
 				desiredWith: 0,
 			},
-			want: `
+			want: asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123ABABABABABAB123123║
@@ -532,64 +533,64 @@ func TestAlignBoxes(t *testing.T) {
 ║      123123123123      ║
 ║123123123123123123123123║
 ╚════════════════════════╝
-`,
+`),
 		},
 		{
 			name: "not enough space should result in multiple rows",
 			args: args{
 				boxes: []AsciiBox{
-					`
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123ABABABABABAB123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123123123123123123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123ABABABABABAB123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123123123123123123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123ABABABABABAB123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123123123123123123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123ABABABABABAB123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123123123123123123123║
 ╚════════════════════════╝
-`,
+`),
 				},
 				desiredWith: 65,
 			},
-			want: `
+			want: asciiBox(`
 ╔═sampleField════════════╗╔═sampleField════════════╗
 ║      123123123123      ║║      123123123123      ║
 ║123123ABABABABABAB123123║║123123123123123123123123║
@@ -606,64 +607,64 @@ func TestAlignBoxes(t *testing.T) {
 ║      123123123123      ║║      123123123123      ║
 ║123123ABABABABABAB123123║║123123123123123123123123║
 ╚════════════════════════╝╚════════════════════════╝
-`,
+`),
 		},
 		{
 			name: "not enough space should result in multiple rows (3 columns)",
 			args: args{
 				boxes: []AsciiBox{
-					`
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123ABABABABABAB123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123123123123123123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123ABABABABABAB123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123123123123123123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123ABABABABABAB123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123123123123123123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123ABABABABABAB123123║
 ╚════════════════════════╝
-`,
-					`
+`),
+					asciiBox(`
 ╔═sampleField════════════╗
 ║      123123123123      ║
 ║123123123123123123123123║
 ╚════════════════════════╝
-`,
+`),
 				},
 				desiredWith: 78,
 			},
-			want: `
+			want: asciiBox(`
 ╔═sampleField════════════╗╔═sampleField════════════╗╔═sampleField════════════╗
 ║      123123123123      ║║      123123123123      ║║      123123123123      ║
 ║123123ABABABABABAB123123║║123123123123123123123123║║123123ABABABABABAB123123║
@@ -676,7 +677,7 @@ func TestAlignBoxes(t *testing.T) {
 ║      123123123123      ║║      123123123123      ║                          
 ║123123ABABABABABAB123123║║123123123123123123123123║                          
 ╚════════════════════════╝╚════════════════════════╝                          
-`,
+`),
 		},
 	}
 	for _, tt := range tests {
@@ -685,7 +686,7 @@ func TestAlignBoxes(t *testing.T) {
 				tt.args.boxes[i] = trimBox(box)
 			}
 			tt.want = trimBox(tt.want)
-			if got := AlignBoxes(tt.args.boxes, tt.args.desiredWith); got != tt.want {
+			if got := AsciiBoxWriterDefault.AlignBoxes(tt.args.boxes, tt.args.desiredWith); got != tt.want {
 				t.Errorf("AlignBoxes() = '\n%v\n', want '\n%v\n'", got, tt.want)
 			}
 		})
@@ -700,20 +701,20 @@ func TestAsciiBox_width(t *testing.T) {
 	}{
 		{
 			name: "same width",
-			m: `
+			m: asciiBox(`
 123123123123123
 123123123123123
 123123123123123
-`,
+`),
 			want: 15,
 		},
 		{
 			name: "different width",
-			m: `
+			m: asciiBox(`
 123123123123123
 123123123123123123123123123123
 123123123123123
-`,
+`),
 			want: 30,
 		},
 	}
@@ -739,55 +740,55 @@ func Test_mergeHorizontal(t *testing.T) {
 			name: "3 same",
 			args: args{
 				boxes: []AsciiBox{
-					`
+					asciiBox(`
 123123123
 123123123
 123123123
-`,
-					`
+`),
+					asciiBox(`
 abcabcabc
 abcabcabc
 abcabcabc
-`,
-					`
+`),
+					asciiBox(`
 zxyzxyzxy
 zxyzxyzxy
 zxyzxyzxy
-`,
+`),
 				},
 			},
-			want: `
+			want: asciiBox(`
 123123123abcabcabczxyzxyzxy
 123123123abcabcabczxyzxyzxy
 123123123abcabcabczxyzxyzxy
-`,
+`),
 		},
 		{
 			name: "3 different",
 			args: args{
 				boxes: []AsciiBox{
-					`
+					asciiBox(`
 123123123
 123123123
 123123123
-`,
-					`
+`),
+					asciiBox(`
 abcabcabc
 abcabcabcabcabcabcabcabcabc
 abcabcabc
-`,
-					`
+`),
+					asciiBox(`
 zxyzxyzxy
 zxyzxyzxy
 zxyzxyzxy
-`,
+`),
 				},
 			},
-			want: `
+			want: asciiBox(`
 123123123abcabcabc                  zxyzxyzxy
 123123123abcabcabcabcabcabcabcabcabczxyzxyzxy
 123123123abcabcabc                  zxyzxyzxy
-`,
+`),
 		},
 	}
 	for _, tt := range tests {
@@ -796,7 +797,7 @@ zxyzxyzxy
 				tt.args.boxes[i] = trimBox(box)
 			}
 			tt.want = trimBox(tt.want)
-			if got := mergeHorizontal(tt.args.boxes); got != tt.want {
+			if got := AsciiBoxWriterDefault.(*asciiBoxWriter).mergeHorizontal(tt.args.boxes); got != tt.want {
 				t.Errorf("mergeHorizontal() = '\n%v\n', want '\n%v\n'", got, tt.want)
 			}
 		})
@@ -816,30 +817,30 @@ func TestExpandBox(t *testing.T) {
 		{
 			name: "Small expand",
 			args: args{
-				box: `
+				box: asciiBox(`
 123123123
 123123123
 123123123
-`,
+`),
 				width: 100,
 			},
-			want: `
+			want: asciiBox(`
 123123123                                                                                           
 123123123                                                                                           
 123123123                                                                                           
-`,
+`),
 		},
 		{
 			name: "Big expand",
 			args: args{
-				box: `
+				box: asciiBox(`
 123123123
 123123123
 123123123
-`,
+`),
 				width: 10000,
 			},
-			want: AsciiBox(fmt.Sprintf(`
+			want: asciiBox(fmt.Sprintf(`
 123123123%[1]s
 123123123%[1]s
 123123123%[1]s
@@ -850,7 +851,7 @@ func TestExpandBox(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 			tt.args.box = trimBox(tt.args.box)
 			tt.want = trimBox(tt.want)
-			if got := expandBox(tt.args.box, tt.args.width); got != tt.want {
+			if got := AsciiBoxWriterDefault.(*asciiBoxWriter).expandBox(tt.args.box, tt.args.width); got != tt.want {
 				t.Errorf("mergeHorizontal() = '\n%v\n', want '\n%v\n'", got, tt.want)
 			}
 		})
@@ -861,14 +862,18 @@ func BenchmarkExpandBox(b *testing.B) {
 	oldSetting := DebugAsciiBox
 	DebugAsciiBox = false
 	bigString := strings.Repeat(strings.Repeat("LoreIpsum", 100)+"\n", 100)
-	box := BoxString("RandomBox", bigString, 100)
+	box := AsciiBoxWriterDefault.BoxString("RandomBox", bigString, 100)
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
-		expandBox(box, 10000)
+		AsciiBoxWriterDefault.(*asciiBoxWriter).expandBox(box, 10000)
 	}
 	DebugAsciiBox = oldSetting
 }
 
 func trimBox(box AsciiBox) AsciiBox {
-	return AsciiBox(strings.Trim(box.String(), "\n"))
+	return AsciiBox{strings.Trim(box.String(), "\n"), AsciiBoxWriterDefault.(*asciiBoxWriter)}
+}
+
+func asciiBox(value string) AsciiBox {
+	return AsciiBox{value, AsciiBoxWriterDefault.(*asciiBoxWriter)}
 }
diff --git a/plc4go/internal/plc4go/spi/utils/dumpUtils.go b/plc4go/internal/plc4go/spi/utils/dumpUtils.go
index 93ceb21..5965fe9 100644
--- a/plc4go/internal/plc4go/spi/utils/dumpUtils.go
+++ b/plc4go/internal/plc4go/spi/utils/dumpUtils.go
@@ -28,24 +28,24 @@ import (
 
 // BoxedDump dumps a 56+2 char wide hex string
 func BoxedDump(name string, data []byte) AsciiBox {
-	return BoxString(name, DumpFixedWidth(data, DefaultWidth), DefaultWidth+boxLineOverheat)
+	return AsciiBoxWriterDefault.BoxString(name, DumpFixedWidth(data, DefaultWidth), DefaultWidth+boxLineOverheat)
 }
 
 // BoxedDumpFixedWidth dumps a hex into a beautiful box
 func BoxedDumpFixedWidth(name string, data []byte, charWidth int) AsciiBox {
 	// we substract the 2 lines at the side
 	dumpWidth := charWidth - 1 - 1
-	return BoxString(name, DumpFixedWidth(data, dumpWidth), charWidth)
+	return AsciiBoxWriterDefault.BoxString(name, DumpFixedWidth(data, dumpWidth), charWidth)
 }
 
 // BoxedDumpAnything dumps anything as hex into a beautiful box
 func BoxedDumpAnything(name string, anything interface{}) AsciiBox {
-	return BoxString(name, DumpAnything(anything), 0)
+	return AsciiBoxWriterDefault.BoxString(name, DumpAnything(anything), 0)
 }
 
 // BoxedDumpAnythingFixedWidth dumps anything as hex into a beautiful box with a given width
 func BoxedDumpAnythingFixedWidth(name string, anything interface{}, charWidth int) AsciiBox {
-	return BoxString(name, DumpAnythingFixedWidth(anything, charWidth), 0)
+	return AsciiBoxWriterDefault.BoxString(name, DumpAnythingFixedWidth(anything, charWidth), 0)
 }
 
 // DumpAnything dumps anything as hex
@@ -68,10 +68,10 @@ func DumpAnythingFixedWidth(anything interface{}, charWidth int) string {
 func BoxAnything(name string, anything interface{}, charWidth int) AsciiBox {
 	switch anything.(type) {
 	case nil:
-		return ""
+		return AsciiBox{asciiBoxWriter: AsciiBoxWriterDefault.(*asciiBoxWriter)}
 	case AsciiBoxer:
 		if reflect.ValueOf(anything).IsNil() {
-			return ""
+			return AsciiBox{asciiBoxWriter: AsciiBoxWriterDefault.(*asciiBoxWriter)}
 		}
 		// A box usually has its own name
 		return anything.(AsciiBoxer).Box(name, charWidth)
@@ -80,38 +80,38 @@ func BoxAnything(name string, anything interface{}, charWidth int) AsciiBox {
 		if anything.(bool) {
 			asInt = 1
 		}
-		return BoxString(name, fmt.Sprintf("b%d %t", asInt, anything), 0)
+		return AsciiBoxWriterDefault.BoxString(name, fmt.Sprintf("b%d %t", asInt, anything), 0)
 	case uint, uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64:
 		hexDigits := reflect.TypeOf(anything).Bits() / 4
-		return BoxString(name, fmt.Sprintf("%#0*x %d", hexDigits, anything, anything), 0)
+		return AsciiBoxWriterDefault.BoxString(name, fmt.Sprintf("%#0*x %d", hexDigits, anything, anything), 0)
 	case []byte:
-		return AsciiBox(DumpFixedWidth(anything.([]byte), charWidth))
+		return AsciiBox{DumpFixedWidth(anything.([]byte), charWidth), AsciiBoxWriterDefault.(*asciiBoxWriter)}
 	case string:
-		return BoxString(name, anything.(string), charWidth)
+		return AsciiBoxWriterDefault.BoxString(name, anything.(string), charWidth)
 	case fmt.Stringer:
-		return BoxString(name, anything.(fmt.Stringer).String(), 0)
+		return AsciiBoxWriterDefault.BoxString(name, anything.(fmt.Stringer).String(), 0)
 	default:
 		valueOf := reflect.ValueOf(anything)
 		if valueOf.IsNil() {
-			return ""
+			return AsciiBox{asciiBoxWriter: AsciiBoxWriterDefault.(*asciiBoxWriter)}
 		}
 		switch valueOf.Kind() {
 		case reflect.Bool:
-			return BoxString(name, fmt.Sprintf("%t", anything), 0)
+			return AsciiBoxWriterDefault.BoxString(name, fmt.Sprintf("%t", anything), 0)
 		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int,
 			reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float32, reflect.Float64:
-			return BoxString(name, fmt.Sprintf("%#0*x %d", unsafe.Sizeof(valueOf.Elem())/2, valueOf.Elem(), anything), 0)
+			return AsciiBoxWriterDefault.BoxString(name, fmt.Sprintf("%#0*x %d", unsafe.Sizeof(valueOf.Elem())/2, valueOf.Elem(), anything), 0)
 		case reflect.Slice, reflect.Array:
 			boxes := make([]AsciiBox, valueOf.Len())
 			for i := 0; i < valueOf.Len(); i++ {
 				index := valueOf.Index(i)
 				boxes[i] = BoxAnything("", index.Interface(), charWidth-2)
 			}
-			return BoxBox(name, AlignBoxes(boxes, charWidth), 0)
+			return AsciiBoxWriterDefault.BoxBox(name, AsciiBoxWriterDefault.AlignBoxes(boxes, charWidth), 0)
 		case reflect.Ptr, reflect.Uintptr:
 			return BoxAnything(name, valueOf.Elem().Interface(), charWidth)
 		default:
-			return BoxString(name, fmt.Sprintf("0x%x", anything.(interface{})), charWidth)
+			return AsciiBoxWriterDefault.BoxString(name, fmt.Sprintf("0x%x", anything.(interface{})), charWidth)
 		}
 	}
 }