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

[plc4x] 09/09: refactoring: Updated the plc4net branch to the latest changes on develop. new feature: Now the DataIo generation is almost finished.

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

cdutz pushed a commit to branch feature/plc4net2
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 2775ec998eaba81764a87295e95201b80240ac26
Author: cdutz <ch...@c-ware.de>
AuthorDate: Wed Dec 15 19:06:21 2021 +0100

    refactoring: Updated the plc4net branch to the latest changes on develop.
    new feature: Now the DataIo generation is almost finished.
---
 .../language/cs/CsLanguageTemplateHelper.java      | 1054 ---
 .../resources/templates/cs/data-io-template.ftlh   |  207 -
 .../resources/templates/cs/model-template.ftlh     |  134 -
 .../language-cs/pom.xml                            |   14 +-
 .../apache/plc4x/language/cs/CsLanguageOutput.java |   22 +-
 .../language/cs/CsLanguageTemplateHelper.java      | 1201 +++
 ...x.plugins.codegenerator.language.LanguageOutput |    0
 .../templates/cs/data-io-template.cs.ftlh          |  437 ++
 .../resources/templates/cs/enum-template.cs.ftlh   |   49 +-
 .../resources/templates/cs/io-template.cs.ftlh     |  299 +
 .../resources/templates/cs/model-template.cs.ftlh} |  430 +-
 .../plc4x/language/java/JavaLanguageOutput.java    |    2 +-
 ...template.java.ftlh => model-template.java.ftlh} |    0
 code-generation/pom.xml                            |   37 +-
 .../knxnetip/readwrite/model/KnxManufacturer.go    |   26 +-
 sandbox/plc4net/api/api/value/IPlcValue.cs         |    2 +-
 .../knxnetip/ParserSerializerTestsuite.xml         |  939 ++-
 .../knxnetip/readwrite/model/KnxDatapointTests.cs  |    2 +-
 .../drivers/knxnetip/plc4net-driver-knxproj.csproj |    4 +
 .../knxnetip/readwrite/model/AccessLevel.cs        |   89 +
 .../src/drivers/knxnetip/readwrite/model/Apdu.cs   |   49 +
 .../knxnetip/readwrite/model/ApduControl.cs        |   43 +
 .../knxnetip/readwrite/model/ApduControlAck.cs     |   43 +
 .../knxnetip/readwrite/model/ApduControlConnect.cs |   43 +
 .../readwrite/model/ApduControlContainer.cs        |   48 +
 .../readwrite/model/ApduControlDisconnect.cs       |   43 +
 .../knxnetip/readwrite/model/ApduControlNack.cs    |   43 +
 .../drivers/knxnetip/readwrite/model/ApduData.cs   |   43 +
 .../knxnetip/readwrite/model/ApduDataAdcRead.cs    |   43 +
 .../readwrite/model/ApduDataAdcResponse.cs         |   43 +
 .../knxnetip/readwrite/model/ApduDataContainer.cs  |   48 +
 .../model/ApduDataDeviceDescriptorRead.cs          |   47 +
 .../model/ApduDataDeviceDescriptorResponse.cs      |   49 +
 .../knxnetip/readwrite/model/ApduDataExt.cs        |   43 +
 .../readwrite/model/ApduDataExtAuthorizeRequest.cs |   49 +
 .../model/ApduDataExtAuthorizeResponse.cs          |   47 +
 .../model/ApduDataExtDomainAddressRead.cs          |   43 +
 .../model/ApduDataExtDomainAddressResponse.cs      |   43 +
 .../model/ApduDataExtDomainAddressSelectiveRead.cs |   43 +
 .../ApduDataExtDomainAddressSerialNumberRead.cs    |   43 +
 ...ApduDataExtDomainAddressSerialNumberResponse.cs |   43 +
 .../ApduDataExtDomainAddressSerialNumberWrite.cs   |   43 +
 .../model/ApduDataExtDomainAddressWrite.cs         |   43 +
 .../model/ApduDataExtFileStreamInfoReport.cs       |   43 +
 .../ApduDataExtGroupPropertyValueInfoReport.cs     |   43 +
 .../model/ApduDataExtGroupPropertyValueRead.cs     |   43 +
 .../model/ApduDataExtGroupPropertyValueResponse.cs |   43 +
 .../model/ApduDataExtGroupPropertyValueWrite.cs    |   43 +
 ...ApduDataExtIndividualAddressSerialNumberRead.cs |   43 +
 ...DataExtIndividualAddressSerialNumberResponse.cs |   43 +
 ...pduDataExtIndividualAddressSerialNumberWrite.cs |   43 +
 .../readwrite/model/ApduDataExtKeyResponse.cs      |   43 +
 .../readwrite/model/ApduDataExtKeyWrite.cs         |   43 +
 .../readwrite/model/ApduDataExtLinkRead.cs         |   43 +
 .../readwrite/model/ApduDataExtLinkResponse.cs     |   43 +
 .../readwrite/model/ApduDataExtLinkWrite.cs        |   43 +
 .../readwrite/model/ApduDataExtMemoryBitWrite.cs   |   43 +
 .../model/ApduDataExtNetworkParameterRead.cs       |   43 +
 .../model/ApduDataExtNetworkParameterResponse.cs   |   43 +
 .../model/ApduDataExtNetworkParameterWrite.cs      |   43 +
 .../model/ApduDataExtOpenRoutingTableRequest.cs    |   43 +
 .../model/ApduDataExtPropertyDescriptionRead.cs    |   51 +
 .../ApduDataExtPropertyDescriptionResponse.cs      |   61 +
 .../model/ApduDataExtPropertyValueRead.cs          |   53 +
 .../model/ApduDataExtPropertyValueResponse.cs      |   55 +
 .../model/ApduDataExtPropertyValueWrite.cs         |   55 +
 .../model/ApduDataExtReadRouterMemoryRequest.cs    |   43 +
 .../model/ApduDataExtReadRouterMemoryResponse.cs   |   43 +
 .../model/ApduDataExtReadRouterStatusRequest.cs    |   43 +
 .../model/ApduDataExtReadRouterStatusResponse.cs   |   43 +
 .../model/ApduDataExtReadRoutingTableRequest.cs    |   43 +
 .../model/ApduDataExtReadRoutingTableResponse.cs   |   43 +
 .../model/ApduDataExtWriteRouterMemoryRequest.cs   |   43 +
 .../model/ApduDataExtWriteRouterStatusRequest.cs   |   43 +
 .../model/ApduDataExtWriteRoutingTableRequest.cs   |   43 +
 .../readwrite/model/ApduDataGroupValueRead.cs      |   43 +
 .../readwrite/model/ApduDataGroupValueResponse.cs  |   49 +
 .../readwrite/model/ApduDataGroupValueWrite.cs     |   49 +
 .../model/ApduDataIndividualAddressRead.cs         |   43 +
 .../model/ApduDataIndividualAddressResponse.cs     |   43 +
 .../model/ApduDataIndividualAddressWrite.cs        |   43 +
 .../knxnetip/readwrite/model/ApduDataMemoryRead.cs |   49 +
 .../readwrite/model/ApduDataMemoryResponse.cs      |   49 +
 .../readwrite/model/ApduDataMemoryWrite.cs         |   43 +
 .../knxnetip/readwrite/model/ApduDataOther.cs      |   47 +
 .../knxnetip/readwrite/model/ApduDataRestart.cs    |   43 +
 .../readwrite/model/ApduDataUserMessage.cs         |   43 +
 .../src/drivers/knxnetip/readwrite/model/CEMI.cs   |   43 +
 .../readwrite/model/CEMIAdditionalInformation.cs   |   43 +
 .../CEMIAdditionalInformationBusmonitorInfo.cs     |   60 +
 .../CEMIAdditionalInformationRelativeTimestamp.cs  |   50 +
 .../knxnetip/readwrite/model/CEMIPriority.cs       |   34 +
 .../knxnetip/readwrite/model/ChannelInformation.cs |   47 +
 .../knxnetip/readwrite/model/ComObjectTable.cs     |   43 +
 .../readwrite/model/ComObjectTableAddresses.cs     | 7416 +++++++++++++++++++
 .../model/ComObjectTableRealisationType1.cs        |   51 +
 .../model/ComObjectTableRealisationType2.cs        |   51 +
 .../model/ComObjectTableRealisationType6.cs        |   47 +
 .../knxnetip/readwrite/model/ComObjectValueType.cs |  104 +
 .../knxnetip/readwrite/model/ConnectionRequest.cs  |   51 +
 .../model/ConnectionRequestInformation.cs          |   43 +
 ...ConnectionRequestInformationDeviceManagement.cs |   43 +
 ...ConnectionRequestInformationTunnelConnection.cs |   47 +
 .../knxnetip/readwrite/model/ConnectionResponse.cs |   53 +
 .../readwrite/model/ConnectionResponseDataBlock.cs |   43 +
 .../ConnectionResponseDataBlockDeviceManagement.cs |   43 +
 .../ConnectionResponseDataBlockTunnelConnection.cs |   47 +
 .../readwrite/model/ConnectionStateRequest.cs      |   49 +
 .../readwrite/model/ConnectionStateResponse.cs     |   49 +
 .../knxnetip/readwrite/model/DIBDeviceInfo.cs      |   61 +
 .../knxnetip/readwrite/model/DIBSuppSvcFamilies.cs |   47 +
 .../knxnetip/readwrite/model/DescriptionRequest.cs |   47 +
 .../readwrite/model/DescriptionResponse.cs         |   49 +
 .../readwrite/model/DeviceConfigurationAck.cs      |   47 +
 .../model/DeviceConfigurationAckDataBlock.cs       |   49 +
 .../readwrite/model/DeviceConfigurationRequest.cs  |   49 +
 .../model/DeviceConfigurationRequestDataBlock.cs   |   47 +
 .../knxnetip/readwrite/model/DeviceDescriptor.cs   |  257 +
 .../readwrite/model/DeviceDescriptorMediumType.cs  |   36 +
 .../readwrite/model/DeviceDescriptorType2.cs       |   63 +
 .../knxnetip/readwrite/model/DeviceStatus.cs       |   45 +
 .../knxnetip/readwrite/model/DisconnectRequest.cs  |   49 +
 .../knxnetip/readwrite/model/DisconnectResponse.cs |   49 +
 .../knxnetip/readwrite/model/FirmwareType.cs       |   46 +
 .../model/GroupObjectDescriptorRealisationType1.cs |   59 +
 .../model/GroupObjectDescriptorRealisationType2.cs |   61 +
 .../model/GroupObjectDescriptorRealisationType6.cs |   41 +
 .../model/GroupObjectDescriptorRealisationType7.cs |   61 +
 .../model/GroupObjectDescriptorRealisationTypeB.cs |   59 +
 .../readwrite/model/HPAIControlEndpoint.cs         |   49 +
 .../knxnetip/readwrite/model/HPAIDataEndpoint.cs   |   49 +
 .../readwrite/model/HPAIDiscoveryEndpoint.cs       |   49 +
 .../knxnetip/readwrite/model/HostProtocolCode.cs   |   32 +
 .../drivers/knxnetip/readwrite/model/IPAddress.cs  |   45 +
 .../drivers/knxnetip/readwrite/model/KnxAddress.cs |   49 +
 .../knxnetip/readwrite/model/KnxDatapoint.cs       | 7748 ++++++++++++++++++++
 .../readwrite/model/KnxDatapointMainType.cs        |  664 ++
 .../knxnetip/readwrite/model/KnxDatapointType.cs   | 3544 +++++++++
 .../knxnetip/readwrite/model/KnxGroupAddress.cs    |   43 +
 .../readwrite/model/KnxGroupAddress2Level.cs       |   49 +
 .../readwrite/model/KnxGroupAddress3Level.cs       |   51 +
 .../readwrite/model/KnxGroupAddressFreeLevel.cs    |   47 +
 .../readwrite/model/KnxInterfaceObjectProperty.cs  | 2882 ++++++++
 .../readwrite/model/KnxInterfaceObjectType.cs      |  229 +
 .../drivers/knxnetip/readwrite/model/KnxLayer.cs   |   33 +
 .../knxnetip/readwrite/model/KnxManufacturer.cs    | 4065 ++++++++++
 .../drivers/knxnetip/readwrite/model/KnxMedium.cs  |   36 +
 .../knxnetip/readwrite/model/KnxNetIpCore.cs       |   47 +
 .../readwrite/model/KnxNetIpDeviceManagement.cs    |   47 +
 .../knxnetip/readwrite/model/KnxNetIpMessage.cs    |   46 +
 .../knxnetip/readwrite/model/KnxNetIpRouting.cs    |   47 +
 .../knxnetip/readwrite/model/KnxNetIpTunneling.cs  |   47 +
 .../knxnetip/readwrite/model/KnxNetObjectServer.cs |   47 +
 .../model/KnxNetRemoteConfigurationAndDiagnosis.cs |   47 +
 .../readwrite/model/KnxNetRemoteLogging.cs         |   47 +
 .../knxnetip/readwrite/model/KnxProperty.cs        | 1291 ++++
 .../readwrite/model/KnxPropertyDataType.cs         |  564 ++
 .../drivers/knxnetip/readwrite/model/LBusmonInd.cs |   53 +
 .../drivers/knxnetip/readwrite/model/LDataCon.cs   |   51 +
 .../knxnetip/readwrite/model/LDataExtended.cs      |   59 +
 .../drivers/knxnetip/readwrite/model/LDataFrame.cs |   56 +
 .../knxnetip/readwrite/model/LDataFrameACK.cs      |   45 +
 .../drivers/knxnetip/readwrite/model/LDataInd.cs   |   51 +
 .../drivers/knxnetip/readwrite/model/LDataReq.cs   |   51 +
 .../drivers/knxnetip/readwrite/model/LPollData.cs  |   53 +
 .../knxnetip/readwrite/model/LPollDataCon.cs       |   43 +
 .../knxnetip/readwrite/model/LPollDataReq.cs       |   43 +
 .../drivers/knxnetip/readwrite/model/LRawCon.cs    |   43 +
 .../drivers/knxnetip/readwrite/model/LRawInd.cs    |   43 +
 .../drivers/knxnetip/readwrite/model/LRawReq.cs    |   43 +
 .../drivers/knxnetip/readwrite/model/MACAddress.cs |   45 +
 .../readwrite/model/MFuncPropCommandReq.cs         |   43 +
 .../knxnetip/readwrite/model/MFuncPropCon.cs       |   43 +
 .../readwrite/model/MFuncPropStateReadReq.cs       |   43 +
 .../knxnetip/readwrite/model/MPropInfoInd.cs       |   43 +
 .../knxnetip/readwrite/model/MPropReadCon.cs       |   57 +
 .../knxnetip/readwrite/model/MPropReadReq.cs       |   55 +
 .../knxnetip/readwrite/model/MPropWriteCon.cs      |   43 +
 .../knxnetip/readwrite/model/MPropWriteReq.cs      |   43 +
 .../drivers/knxnetip/readwrite/model/MResetInd.cs  |   43 +
 .../drivers/knxnetip/readwrite/model/MResetReq.cs  |   43 +
 .../model/ProjectInstallationIdentifier.cs         |   47 +
 .../knxnetip/readwrite/model/RelativeTimestamp.cs  |   45 +
 .../knxnetip/readwrite/model/RoutingIndication.cs  |   43 +
 .../knxnetip/readwrite/model/SearchRequest.cs      |   47 +
 .../knxnetip/readwrite/model/SearchResponse.cs     |   51 +
 .../drivers/knxnetip/readwrite/model/ServiceId.cs  |   43 +
 .../src/drivers/knxnetip/readwrite/model/Status.cs |   42 +
 .../readwrite/model/SupportedPhysicalMedia.cs      |   46 +-
 .../knxnetip/readwrite/model/TDataConnectedInd.cs  |   43 +
 .../knxnetip/readwrite/model/TDataConnectedReq.cs  |   43 +
 .../knxnetip/readwrite/model/TDataIndividualInd.cs |   43 +
 .../knxnetip/readwrite/model/TDataIndividualReq.cs |   43 +
 .../knxnetip/readwrite/model/TunnelingRequest.cs   |   49 +
 .../readwrite/model/TunnelingRequestDataBlock.cs   |   47 +
 .../knxnetip/readwrite/model/TunnelingResponse.cs  |   47 +
 .../readwrite/model/TunnelingResponseDataBlock.cs  |   49 +
 .../knxnetip/readwrite/model/UnknownMessage.cs     |   47 +
 .../knxnetip/src/knxnetip/readwrite/model/APCI.cs  |   46 -
 .../knxnetip/src/knxnetip/readwrite/model/CEMI.cs  |   34 -
 .../readwrite/model/CEMIAdditionalInformation.cs   |   34 -
 .../CEMIAdditionalInformationBusmonitorInfo.cs     |   53 -
 .../CEMIAdditionalInformationRelativeTimestamp.cs  |   43 -
 .../src/knxnetip/readwrite/model/CEMIBusmonInd.cs  |   44 -
 .../src/knxnetip/readwrite/model/CEMIDataCon.cs    |   44 -
 .../src/knxnetip/readwrite/model/CEMIDataFrame.cs  |   70 -
 .../src/knxnetip/readwrite/model/CEMIDataInd.cs    |   44 -
 .../src/knxnetip/readwrite/model/CEMIDataReq.cs    |   44 -
 .../src/knxnetip/readwrite/model/CEMIFrame.cs      |   46 -
 .../src/knxnetip/readwrite/model/CEMIFrameAck.cs   |   43 -
 .../src/knxnetip/readwrite/model/CEMIFrameData.cs  |   67 -
 .../knxnetip/readwrite/model/CEMIFrameDataExt.cs   |   69 -
 .../readwrite/model/CEMIFramePollingData.cs        |   43 -
 .../readwrite/model/CEMIFramePollingDataExt.cs     |   43 -
 .../knxnetip/readwrite/model/CEMIMPropReadCon.cs   |   50 -
 .../knxnetip/readwrite/model/CEMIMPropReadReq.cs   |   48 -
 .../knxnetip/readwrite/model/CEMIPollDataCon.cs    |   36 -
 .../knxnetip/readwrite/model/CEMIPollDataReq.cs    |   36 -
 .../src/knxnetip/readwrite/model/CEMIPriority.cs   |   34 -
 .../src/knxnetip/readwrite/model/CEMIRawCon.cs     |   36 -
 .../src/knxnetip/readwrite/model/CEMIRawInd.cs     |   36 -
 .../src/knxnetip/readwrite/model/CEMIRawReq.cs     |   36 -
 .../knxnetip/readwrite/model/ConnectionRequest.cs  |   44 -
 .../model/ConnectionRequestInformation.cs          |   34 -
 ...ConnectionRequestInformationDeviceManagement.cs |   36 -
 ...ConnectionRequestInformationTunnelConnection.cs |   40 -
 .../knxnetip/readwrite/model/ConnectionResponse.cs |   46 -
 .../readwrite/model/ConnectionResponseDataBlock.cs |   34 -
 .../ConnectionResponseDataBlockDeviceManagement.cs |   36 -
 .../ConnectionResponseDataBlockTunnelConnection.cs |   40 -
 .../readwrite/model/ConnectionStateRequest.cs      |   42 -
 .../readwrite/model/ConnectionStateResponse.cs     |   42 -
 .../src/knxnetip/readwrite/model/DIBDeviceInfo.cs  |   52 -
 .../knxnetip/readwrite/model/DIBSuppSvcFamilies.cs |   38 -
 .../knxnetip/readwrite/model/DescriptionRequest.cs |   40 -
 .../readwrite/model/DescriptionResponse.cs         |   42 -
 .../readwrite/model/DeviceConfigurationAck.cs      |   40 -
 .../model/DeviceConfigurationAckDataBlock.cs       |   40 -
 .../readwrite/model/DeviceConfigurationRequest.cs  |   42 -
 .../model/DeviceConfigurationRequestDataBlock.cs   |   38 -
 .../src/knxnetip/readwrite/model/DeviceStatus.cs   |   36 -
 .../knxnetip/readwrite/model/DisconnectRequest.cs  |   42 -
 .../knxnetip/readwrite/model/DisconnectResponse.cs |   42 -
 .../readwrite/model/HPAIControlEndpoint.cs         |   40 -
 .../knxnetip/readwrite/model/HPAIDataEndpoint.cs   |   40 -
 .../readwrite/model/HPAIDiscoveryEndpoint.cs       |   40 -
 .../knxnetip/readwrite/model/HostProtocolCode.cs   |   32 -
 .../src/knxnetip/readwrite/model/IPAddress.cs      |   36 -
 .../src/knxnetip/readwrite/model/KnxAddress.cs     |   40 -
 .../src/knxnetip/readwrite/model/KnxDatapoint.cs   | 3956 ----------
 .../knxnetip/readwrite/model/KnxDatapointType.cs   | 3634 ---------
 .../knxnetip/readwrite/model/KnxGroupAddress.cs    |   34 -
 .../readwrite/model/KnxGroupAddress2Level.cs       |   42 -
 .../readwrite/model/KnxGroupAddress3Level.cs       |   44 -
 .../readwrite/model/KnxGroupAddressFreeLevel.cs    |   40 -
 .../src/knxnetip/readwrite/model/KnxLayer.cs       |   33 -
 .../src/knxnetip/readwrite/model/KnxMedium.cs      |   36 -
 .../src/knxnetip/readwrite/model/KnxNetIpCore.cs   |   40 -
 .../readwrite/model/KnxNetIpDeviceManagement.cs    |   40 -
 .../knxnetip/readwrite/model/KnxNetIpMessage.cs    |   37 -
 .../knxnetip/readwrite/model/KnxNetIpTunneling.cs  |   40 -
 .../knxnetip/readwrite/model/KnxNetObjectServer.cs |   40 -
 .../model/KnxNetRemoteConfigurationAndDiagnosis.cs |   40 -
 .../readwrite/model/KnxNetRemoteLogging.cs         |   40 -
 .../src/knxnetip/readwrite/model/MACAddress.cs     |   36 -
 .../model/ProjectInstallationIdentifier.cs         |   38 -
 .../knxnetip/readwrite/model/RelativeTimestamp.cs  |   36 -
 .../knxnetip/readwrite/model/RoutingIndication.cs  |   36 -
 .../src/knxnetip/readwrite/model/SearchRequest.cs  |   40 -
 .../src/knxnetip/readwrite/model/SearchResponse.cs |   44 -
 .../src/knxnetip/readwrite/model/ServiceId.cs      |   34 -
 .../src/knxnetip/readwrite/model/Status.cs         |   42 -
 .../knxnetip/src/knxnetip/readwrite/model/TPCI.cs  |   34 -
 .../knxnetip/readwrite/model/TunnelingRequest.cs   |   42 -
 .../readwrite/model/TunnelingRequestDataBlock.cs   |   38 -
 .../knxnetip/readwrite/model/TunnelingResponse.cs  |   40 -
 .../readwrite/model/TunnelingResponseDataBlock.cs  |   40 -
 .../src/knxnetip/readwrite/model/UnknownMessage.cs |   40 -
 sandbox/plc4net/plc4net.driver/pom.xml             |   67 -
 sandbox/plc4net/pom.xml                            |    6 +-
 sandbox/plc4net/spi/spi/generation/ByteOrder.cs    |   27 +
 .../plc4net/spi/spi/generation/EvaluationHelper.cs |   74 +
 .../plc4net/spi/spi/generation/ParseException.cs   |   26 +
 sandbox/plc4net/spi/spi/generation/ReadBuffer.cs   |   46 +-
 sandbox/plc4net/spi/spi/generation/WriteBuffer.cs  |   26 +-
 sandbox/plc4net/spi/spi/model/values/PlcTIME.cs    |    4 +-
 .../spi/spi/model/values/PlcValueAdapter.cs        |    2 +-
 src/main/script/prerequisiteCheck.groovy           |    8 -
 288 files changed, 39604 insertions(+), 12907 deletions(-)

diff --git a/build-utils/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageTemplateHelper.java b/build-utils/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageTemplateHelper.java
deleted file mode 100644
index d144a0e..0000000
--- a/build-utils/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageTemplateHelper.java
+++ /dev/null
@@ -1,1054 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-
-package org.apache.plc4x.language.cs;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.math.NumberUtils;
-import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.BaseFreemarkerLanguageTemplateHelper;
-import org.apache.plc4x.plugins.codegenerator.types.definitions.*;
-import org.apache.plc4x.plugins.codegenerator.types.enums.EnumValue;
-import org.apache.plc4x.plugins.codegenerator.types.fields.*;
-import org.apache.plc4x.plugins.codegenerator.types.references.*;
-import org.apache.plc4x.plugins.codegenerator.types.terms.*;
-
-import java.util.*;
-
-@SuppressWarnings({"unused", "WeakerAccess"})
-public class CsLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelper {
-
-    public CsLanguageTemplateHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types) {
-        super(thisType, protocolName, flavorName, types);
-    }
-
-    public String fileName(String protocolName, String languageName, String languageFlavorName) {
-        return String.join("", protocolName.split("\\-")) + "." +
-            String.join("", languageFlavorName.split("\\-"));
-    }
-
-    public String packageName(String languageFlavorName) {
-        return String.join("", languageFlavorName.split("\\-"));
-    }
-
-    @Override
-    public String getLanguageTypeNameForField(Field field) {
-        boolean optional = field instanceof OptionalField;
-        // If the referenced type is a DataIo type, the value is of type PlcValue.
-        if(field instanceof PropertyField) {
-            PropertyField propertyField = (PropertyField) field;
-            if(propertyField.getType() instanceof ComplexTypeReference) {
-                ComplexTypeReference complexTypeReference = (ComplexTypeReference) propertyField.getType();
-                final TypeDefinition typeDefinition = getTypeDefinitions().get(complexTypeReference.getName());
-                if(typeDefinition instanceof DataIoTypeDefinition) {
-                    return "PlcValue";
-                }
-            }
-        }
-        return getLanguageTypeNameForTypeReference(((TypedField) field).getType());
-    }
-
-    @Override
-    public String getLanguageTypeNameForTypeReference(TypeReference typeReference) {
-        if(typeReference instanceof SimpleTypeReference) {
-            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
-            switch (simpleTypeReference.getBaseType()) {
-                case BIT: {
-                    return "bool";
-                }
-                case UINT: {
-                    IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                    if (integerTypeReference.getSizeInBits() <= 8) {
-                        return "byte";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 16) {
-                        return "ushort";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 32) {
-                        return "uint";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 64) {
-                        return "ulong";
-                    }
-                    throw new RuntimeException("Unsupported simple type");
-                }
-                case INT: {
-                    IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                    if (integerTypeReference.getSizeInBits() <= 8) {
-                        return "sbyte";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 16) {
-                        return "short";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 32) {
-                        return "int";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 64) {
-                        return "long";
-                    }
-                    throw new RuntimeException("Unsupported simple type");
-                }
-                case FLOAT:
-                case UFLOAT: {
-                    FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
-                    int sizeInBits = ((floatTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.FLOAT) ? 1 : 0) +
-                        floatTypeReference.getExponent() + floatTypeReference.getMantissa();
-                    if (sizeInBits <= 32) {
-                        return "float";
-                    }
-                    if (sizeInBits <= 64) {
-                        return "double";
-                    }
-                    throw new RuntimeException("Unsupported simple type");
-                }
-                case STRING: {
-                    return "string";
-                }
-                case TIME: {
-                    return "time";
-                }
-                case DATE: {
-                    return "date";
-                }
-                case DATETIME: {
-                    return "datetime2";
-                }
-            }
-            throw new RuntimeException("Unsupported simple type");
-        } else {
-            return (typeReference != null) ? ((ComplexTypeReference) typeReference).getName() : "";
-        }
-    }
-
-    public String getPlcValueTypeForTypeReference(TypeReference typeReference) {
-        if(typeReference instanceof SimpleTypeReference) {
-            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
-            switch (simpleTypeReference.getBaseType()) {
-                case BIT: {
-                    return "PlcBOOL";
-                }
-                case UINT: {
-                    IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                    if (integerTypeReference.getSizeInBits() <= 8) {
-                        return "PlcUSINT";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 16) {
-                        return "PlcUINT";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 32) {
-                        return "PlcUDINT";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 64) {
-                        return "PlcULINT";
-                    }
-                    throw new RuntimeException("Unsupported simple type");
-                }
-                case INT: {
-                    IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                    if (integerTypeReference.getSizeInBits() <= 8) {
-                        return "PlcSINT";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 16) {
-                        return "PlcINT";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 32) {
-                        return "PlcDINT";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 64) {
-                        return "PlcLINT";
-                    }
-                    throw new RuntimeException("Unsupported simple type");
-                }
-                case FLOAT:
-                case UFLOAT: {
-                    FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
-                    int sizeInBits = ((floatTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.FLOAT) ? 1 : 0) +
-                        floatTypeReference.getExponent() + floatTypeReference.getMantissa();
-                    if (sizeInBits <= 32) {
-                        return "PlcREAL";
-                    }
-                    if (sizeInBits <= 64) {
-                        return "PlcLREAL";
-                    }
-                    throw new RuntimeException("Unsupported simple type");
-                }
-                case STRING: {
-                    return "PlcSTRING";
-                }
-                case TIME: {
-                    return "PlcTIME";
-                }
-                case DATE: {
-                    return "PlcDATE";
-                }
-                case DATETIME: {
-                    return "PlcDATE_AND_TIME";
-                }
-            }
-            throw new RuntimeException("Unsupported simple type");
-        } else {
-            return (typeReference != null) ? ((ComplexTypeReference) typeReference).getName() : "";
-        }
-    }
-
-    @Override
-    public String getNullValueForTypeReference(TypeReference typeReference) {
-        if(typeReference instanceof SimpleTypeReference) {
-            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
-            switch (simpleTypeReference.getBaseType()) {
-                case BIT: {
-                    return "false";
-                }
-                case UINT:
-                case INT: {
-                    return "0";
-                }
-                case FLOAT: {
-                    return "0.0";
-                }
-                case STRING: {
-                    return "\"\"";
-                }
-            }
-        } else if(typeReference instanceof ComplexTypeReference) {
-            return "0";
-        }
-        return "null";
-    }
-
-    public int getNumBits(SimpleTypeReference simpleTypeReference) {
-        switch (simpleTypeReference.getBaseType()) {
-            case BIT: {
-                return 1;
-            }
-            case UINT:
-            case INT: {
-                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                return integerTypeReference.getSizeInBits();
-            }
-            case FLOAT: {
-                FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
-                return floatTypeReference.getSizeInBits();
-            }
-            case STRING: {
-                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                return integerTypeReference.getSizeInBits();
-            }
-            default: {
-                return 0;
-            }
-        }
-    }
-
-    public String getReadBufferReadMethodCall(SimpleTypeReference simpleTypeReference, String valueString) {
-        switch (simpleTypeReference.getBaseType()) {
-            case BIT: {
-                return "io.ReadBit()";
-            }
-            case UINT: {
-                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                if (integerTypeReference.getSizeInBits() <= 8) {
-                    return "io.ReadByte(" + integerTypeReference.getSizeInBits() + ")";
-                }
-                if (integerTypeReference.getSizeInBits() <= 16) {
-                    return "io.ReadUshort(" + integerTypeReference.getSizeInBits() + ")";
-                }
-                if (integerTypeReference.getSizeInBits() <= 32) {
-                    return "io.ReadUint(" + integerTypeReference.getSizeInBits() + ")";
-                }
-                if (integerTypeReference.getSizeInBits() <= 64) {
-                    return "io.ReadUlong(" + integerTypeReference.getSizeInBits() + ")";
-                }
-            }
-            case INT: {
-                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                if (integerTypeReference.getSizeInBits() <= 8) {
-                    return "io.ReadSbyte(" + integerTypeReference.getSizeInBits() + ")";
-                }
-                if (integerTypeReference.getSizeInBits() <= 16) {
-                    return "io.ReadShort(" + integerTypeReference.getSizeInBits() + ")";
-                }
-                if (integerTypeReference.getSizeInBits() <= 32) {
-                    return "io.ReadInt(" + integerTypeReference.getSizeInBits() + ")";
-                }
-                if (integerTypeReference.getSizeInBits() <= 64) {
-                    return "io.ReadLong(" + integerTypeReference.getSizeInBits() + ")";
-                }
-            }
-            case FLOAT: {
-                FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
-                if (floatTypeReference.getSizeInBits() <= 32) {
-                    return "io.ReadFloat(true, " + floatTypeReference.getExponent() + ", " + floatTypeReference.getMantissa() + ")";
-                }
-                if (floatTypeReference.getSizeInBits() <= 64) {
-                    return "io.ReadDouble(true, " + floatTypeReference.getExponent() + ", " + floatTypeReference.getMantissa() + ")";
-                }
-            }
-            case STRING: {
-                StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
-                return "io.ReadString(" + stringTypeReference.getSizeInBits() + ", Encoding.GetEncoding(\"" +
-                    stringTypeReference.getEncoding().substring(1, stringTypeReference.getEncoding().length() - 1) + "\"))";
-            }
-        }
-        return "Hurz";
-    }
-
-    @Override
-    public String getWriteBufferWriteMethodCall(SimpleTypeReference simpleTypeReference, String fieldName) {
-        switch (simpleTypeReference.getBaseType()) {
-            case BIT: {
-                return "io.WriteBit(" + fieldName + ")";
-            }
-            case UINT: {
-                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                if (integerTypeReference.getSizeInBits() <= 8) {
-                    return "io.WriteByte(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
-                }
-                if (integerTypeReference.getSizeInBits() <= 16) {
-                    return "io.WriteUshort(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
-                }
-                if (integerTypeReference.getSizeInBits() <= 32) {
-                    return "io.WriteUint(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
-                }
-                if (integerTypeReference.getSizeInBits() <= 64) {
-                    return "io.WriteUlong(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
-                }
-            }
-            case INT: {
-                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                if (integerTypeReference.getSizeInBits() <= 8) {
-                    return "io.WriteSbyte(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
-                }
-                if (integerTypeReference.getSizeInBits() <= 16) {
-                    return "io.WriteShort(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
-                }
-                if (integerTypeReference.getSizeInBits() <= 32) {
-                    return "io.WriteInt(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
-                }
-                if (integerTypeReference.getSizeInBits() <= 64) {
-                    return "io.WriteLong(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
-                }
-            }
-            case FLOAT:
-            case UFLOAT: {
-                FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
-                if (floatTypeReference.getSizeInBits() <= 32) {
-                    return "io.WriteFloat(" + floatTypeReference.getSizeInBits() + ", " + fieldName + ")";
-                }
-                if (floatTypeReference.getSizeInBits() <= 64) {
-                    return "io.WriteDouble(" + floatTypeReference.getSizeInBits() + ", " + fieldName + ")";
-                }
-            }
-            case STRING: {
-                StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
-                String encoding = ((stringTypeReference.getEncoding() != null) && (stringTypeReference.getEncoding().length() > 2)) ?
-                    stringTypeReference.getEncoding().substring(1, stringTypeReference.getEncoding().length() - 1) : "UTF-8";
-                return "io.WriteString(" + stringTypeReference.getSizeInBits() + ", \"" +
-                    encoding + "\", " + fieldName + ")";
-            }
-        }
-        return "Hurz";
-    }
-
-    public String getReservedValue(ReservedField reservedField) {
-        final String languageTypeName = getLanguageTypeNameForTypeReference(reservedField.getType());
-        return reservedField.getReferenceValue().toString();
-    }
-
-    public String toParseExpression(TypedField field, Term term, Argument[] parserArguments) {
-        return toTypedParseExpression((field != null) ? field.getType() : null, term, parserArguments);
-    }
-
-    public String toSerializationExpression(TypedField field, Term term, Argument[] serializerArguments) {
-        return toTypedSerializationExpression((field != null) ? field.getType() : null, term, serializerArguments);
-    }
-
-    public String toBooleanParseExpression(Term term, Argument[] parserArguments) {
-        return toTypedParseExpression(new DefaultBooleanTypeReference(), term, parserArguments);
-    }
-
-    public String toBooleanSerializationExpression(Term term, Argument[] serializerArguments) {
-        return toTypedSerializationExpression(new DefaultBooleanTypeReference(), term, serializerArguments);
-    }
-
-    public String toIntegerParseExpression(int sizeInBits, Term term, Argument[] parserArguments) {
-        return toTypedParseExpression(new DefaultIntegerTypeReference(SimpleTypeReference.SimpleBaseType.UINT, sizeInBits), term, parserArguments);
-    }
-
-    public String toIntegerSerializationExpression(int sizeInBits, Term term, Argument[] serializerArguments) {
-        return toTypedSerializationExpression(new DefaultIntegerTypeReference(SimpleTypeReference.SimpleBaseType.UINT, sizeInBits), term, serializerArguments);
-    }
-
-    public String toTypedParseExpression(TypeReference fieldType, Term term, Argument[] parserArguments) {
-        return toExpression(fieldType, term, parserArguments, null, false, false);
-    }
-
-    public String toTypedSerializationExpression(TypeReference fieldType, Term term, Argument[] serializerArguments) {
-        return toExpression(fieldType, term, null, serializerArguments, true, false);
-    }
-
-    String getCastExpressionForTypeReference(TypeReference typeReference) {
-        if(typeReference instanceof SimpleTypeReference) {
-            return getLanguageTypeNameForTypeReference(typeReference);
-        } else if(typeReference != null) {
-            return "Cast" + getLanguageTypeNameForTypeReference(typeReference);
-        } else {
-            return "";
-        }
-    }
-
-    private String toExpression(TypeReference fieldType, Term term, Argument[] parserArguments, Argument[] serializerArguments, boolean serialize, boolean suppressPointerAccess) {
-        if(term == null) {
-            return "";
-        }
-        if(term instanceof Literal) {
-            if(term instanceof NullLiteral) {
-                return "nil";
-            } else if(term instanceof BooleanLiteral) {
-                return getCastExpressionForTypeReference(fieldType) + "(" + ((BooleanLiteral) term).getValue() + ")";
-            } else if(term instanceof NumericLiteral) {
-                return getCastExpressionForTypeReference(fieldType) + "(" + ((NumericLiteral) term).getNumber().toString() + ")";
-            } else if(term instanceof StringLiteral) {
-                return "\"" + ((StringLiteral) term).getValue() + "\"";
-            } else if(term instanceof VariableLiteral) {
-                return toVariableExpression(fieldType, (VariableLiteral) term, parserArguments, serializerArguments, serialize, suppressPointerAccess);
-            } else {
-                throw new RuntimeException("Unsupported Literal type " + term.getClass().getName());
-            }
-        } else if (term instanceof UnaryTerm) {
-            UnaryTerm ut = (UnaryTerm) term;
-            Term a = ut.getA();
-            switch(ut.getOperation()) {
-                case "!":
-                    return "!(" + toExpression(fieldType, a, parserArguments, serializerArguments, serialize, false) + ")";
-                case "-":
-                    return "-(" + getCastExpressionForTypeReference(fieldType) + "(" + toExpression(fieldType, a, parserArguments, serializerArguments, serialize, false) + "))";
-                case "()":
-                    return getCastExpressionForTypeReference(fieldType) + "(" + toExpression(fieldType, a, parserArguments, serializerArguments, serialize, false) + ")";
-                default:
-                    throw new RuntimeException("Unsupported unary operation type " + ut.getOperation());
-            }
-        } else if (term instanceof BinaryTerm) {
-            BinaryTerm bt = (BinaryTerm) term;
-            Term a = bt.getA();
-            Term b = bt.getB();
-            String operation = bt.getOperation();
-            switch (operation) {
-                case "^":
-                    return "Math.pow(" +
-                        getCastExpressionForTypeReference(fieldType) + "(" + toExpression(fieldType, a, parserArguments, serializerArguments, serialize, false) + "), " +
-                        getCastExpressionForTypeReference(fieldType) + "(" + toExpression(fieldType, b, parserArguments, serializerArguments, serialize, false) + "))";
-                // If we start casting for comparisons, equals or non equals, really messy things happen.
-                case "==":
-                case "!=":
-                case ">":
-                case "<":
-                case ">=":
-                case "<=":
-                    // For every access of optional elements we need pointer access ...
-                    // Except for doing a nil or not-nil check :-(
-                    // So in case of such a check, we need to suppress the pointer-access.
-                    boolean suppressPointerAccessOverride = (operation.equals("==") || operation.equals("!=")) && ((a instanceof NullLiteral) || (b instanceof NullLiteral));
-                    return "bool((" + toExpression(null, a, parserArguments, serializerArguments, serialize, suppressPointerAccessOverride) + ") " +
-                        operation +
-                        " (" + toExpression(null, b, parserArguments, serializerArguments, serialize, suppressPointerAccessOverride) + "))";
-                default:
-                    return getCastExpressionForTypeReference(fieldType) + "(" + toExpression(fieldType, a, parserArguments, serializerArguments, serialize, false) + ") " +
-                        operation + " " +
-                        getCastExpressionForTypeReference(fieldType) +"(" + toExpression(fieldType, b, parserArguments, serializerArguments, serialize, false) + ")";
-            }
-        } else if (term instanceof TernaryTerm) {
-            TernaryTerm tt = (TernaryTerm) term;
-            if ("if".equals(tt.getOperation())) {
-                Term a = tt.getA();
-                Term b = tt.getB();
-                Term c = tt.getC();
-                // TODO: This is not quite correct with the cast to uint16
-                return "utils.InlineIf(" + toExpression(new DefaultBooleanTypeReference(), a, parserArguments, serializerArguments, serialize, false) + ", " +
-                    "uint16(" + toExpression(fieldType, b, parserArguments, serializerArguments, serialize, false) + "), " +
-                    "uint16(" + toExpression(fieldType, c, parserArguments, serializerArguments, serialize, false) + "))";
-            } else {
-                throw new RuntimeException("Unsupported ternary operation type " + tt.getOperation());
-            }
-        } else {
-            throw new RuntimeException("Unsupported Term type " + term.getClass().getName());
-        }
-    }
-
-    private String toVariableExpression(TypeReference typeReference, VariableLiteral vl, Argument[] parserArguments, Argument[] serializerArguments, boolean serialize, boolean suppressPointerAccess) {
-        if ("lengthInBytes".equals(vl.getName())) {
-            return (serialize ? getCastExpressionForTypeReference(typeReference) + "(m." : "") + "LengthInBytes()" + (serialize ? ")" : "");
-        } else if ("lengthInBits".equals(vl.getName())) {
-            return (serialize ? getCastExpressionForTypeReference(typeReference) + "(m." : "") + "LengthInBits()" + (serialize ? ")" : "");
-        }
-        // If this literal references an Enum type, then we have to output it differently.
-        else if (getTypeDefinitions().get(vl.getName()) instanceof EnumTypeDefinition) {
-            return vl.getName() + "_" + vl.getChild().getName() +
-                ((vl.getChild().getChild() != null) ?
-                    "." + toVariableExpression(typeReference, vl.getChild().getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
-        }
-        // If we are accessing enum constants, these also need to be output differently.
-        else if ((getFieldForNameFromCurrent(vl.getName()) instanceof EnumField) && (vl.getChild() != null)) {
-            return vl.getName() + "." + StringUtils.capitalize(vl.getChild().getName()) + "()" +
-                ((vl.getChild().getChild() != null) ?
-                    "." + toVariableExpression(typeReference, vl.getChild().getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
-        }
-        // If we are accessing optional fields of simple type, we need to use pointer-access.
-        else if (!serialize && (getFieldForNameFromCurrent(vl.getName()) instanceof OptionalField) &&
-            (((OptionalField) getFieldForNameFromCurrent(vl.getName())).getType() instanceof SimpleTypeReference)) {
-            return "(*" + vl.getName() + ")" +
-                ((vl.getChild() != null) ?
-                    "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, serialize, suppressPointerAccess) : "");
-        }
-        // CAST expressions are special as we need to add a ".class" to the second parameter in Java.
-        else if ("CAST".equals(vl.getName())) {
-            if ((vl.getArgs() == null) || (vl.getArgs().size() != 2)) {
-                throw new RuntimeException("A CAST expression expects exactly two arguments.");
-            }
-            VariableLiteral typeLiteral = (VariableLiteral) vl.getArgs().get(1);
-            final TypeDefinition typeDefinition = getTypeDefinitions().get(typeLiteral.getName());
-            TypeReference type = typeDefinition.getTypeReference();
-            StringBuilder sb = new StringBuilder();
-            if (type instanceof ComplexTypeReference) {
-                sb.append("Cast");
-            }
-            sb.append(typeLiteral.getName());
-            sb.append("(").append(toVariableExpression(typeReference, (VariableLiteral) vl.getArgs().get(0), parserArguments, serializerArguments, serialize, suppressPointerAccess)).append(")");
-            return sb.toString() + ((vl.getChild() != null) ? "." + StringUtils.capitalize(toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess)) : "");
-        } else if ("STATIC_CALL".equals(vl.getName())) {
-            StringBuilder sb = new StringBuilder();
-            if (!(vl.getArgs().get(0) instanceof StringLiteral)) {
-                throw new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral");
-            }
-            // Get the class and method name
-            String staticCall = ((StringLiteral) vl.getArgs().get(0)).getValue();
-            // Cut off the double-quotes
-            staticCall = staticCall.substring(1, staticCall.length() - 1);
-            // Remove all the previous parts prior to the Class name (Which starts with an uppercase letter)
-            while(staticCall.contains(".") && !StringUtils.isAllUpperCase(staticCall.substring(0,1))) {
-                staticCall = staticCall.substring(staticCall.indexOf(".") + 1);
-            }
-            String className = staticCall.substring(0, staticCall.indexOf("."));
-            String methodName = staticCall.substring(staticCall.indexOf(".") + 1);
-            sb.append(className).append(StringUtils.capitalize(methodName)).append("(");
-            for (int i = 1; i < vl.getArgs().size(); i++) {
-                Term arg = vl.getArgs().get(i);
-                if (i > 1) {
-                    sb.append(", ");
-                }
-                if (arg instanceof VariableLiteral) {
-                    VariableLiteral va = (VariableLiteral) arg;
-                    // "io" is the default name of the reader argument which is always available.
-                    boolean isParserArg = "io".equals(va.getName()) || ((getThisTypeDefinition() instanceof DataIoTypeDefinition) && "_value".equals(va.getName()));
-                    boolean isTypeArg = "_type".equals(va.getName());
-                    if (!isParserArg && !isTypeArg && parserArguments != null) {
-                        for (Argument parserArgument : parserArguments) {
-                            if (parserArgument.getName().equals(va.getName())) {
-                                isParserArg = true;
-                                break;
-                            }
-                        }
-                    }
-                    if (isParserArg) {
-                        if(va.getName().equals("_value")) {
-                            sb.append(va.getName().substring(1) + ((va.getChild() != null) ?
-                                "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : ""));
-                        } else {
-                            sb.append(va.getName() + ((va.getChild() != null) ?
-                                "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : ""));
-                        }
-                    }
-                    // We have to manually evaluate the type information at code-generation time.
-                    else if (isTypeArg) {
-                        String part = va.getChild().getName();
-                        switch (part) {
-                            case "name":
-//                                sb.append("\"").append(field.getTypeName()).append("\"");
-                                break;
-                            case "length":
-                                sb.append("\"").append(((SimpleTypeReference) typeReference).getSizeInBits()).append("\"");
-                                break;
-                            case "encoding":
-                                String encoding = ((StringTypeReference) typeReference).getEncoding();
-                                // Cut off the single quotes.
-                                encoding = encoding.substring(1, encoding.length() - 1);
-                                sb.append("\"").append(encoding).append("\"");
-                                break;
-                        }
-                    } else {
-                        sb.append(toVariableExpression(typeReference, va, parserArguments, serializerArguments, serialize, suppressPointerAccess));
-                    }
-                } else if (arg instanceof StringLiteral) {
-                    sb.append(((StringLiteral) arg).getValue());
-                }
-            }
-            sb.append(")");
-            return sb.toString();
-        } else if ("COUNT".equals(vl.getName())) {
-            return (typeReference instanceof SimpleTypeReference ? getCastExpressionForTypeReference(typeReference) : "") + "(len(" +
-                toVariableExpression(typeReference, (VariableLiteral) vl.getArgs().get(0), parserArguments, serializerArguments, serialize, suppressPointerAccess) +
-                "))";
-        } else if ("ARRAY_SIZE_IN_BYTES".equals(vl.getName())) {
-            VariableLiteral va = (VariableLiteral) vl.getArgs().get(0);
-            // "io" and "m" are always available in every parser.
-            boolean isSerializerArg = "io".equals(va.getName()) || "m".equals(va.getName()) || "element".equals(va.getName());
-            if (!isSerializerArg && serializerArguments != null) {
-                for (Argument serializerArgument : serializerArguments) {
-                    if (serializerArgument.getName().equals(va.getName())) {
-                        isSerializerArg = true;
-                        break;
-                    }
-                }
-            }
-            StringBuilder sb = new StringBuilder();
-            if (isSerializerArg) {
-                sb.append(va.getName()).append(((va.getChild() != null) ? "." + toVariableExpression(typeReference, va.getChild(), parserArguments, serializerArguments, true, suppressPointerAccess) : ""));
-            } else {
-                sb.append(toVariableExpression(typeReference, va, parserArguments, serializerArguments, true, suppressPointerAccess));
-            }
-            return getCastExpressionForTypeReference(typeReference) + "(" + ((VariableLiteral) vl.getArgs().get(0)).getName() + "ArraySizeInBytes(" + sb.toString() + "))";
-        }
-        else if("CEIL".equals(vl.getName())) {
-            Term va = vl.getArgs().get(0);
-            // The Ceil function expects 64 bit floating point values.
-            TypeReference tr = new DefaultFloatTypeReference(SimpleTypeReference.SimpleBaseType.FLOAT, 11, 52);
-            return "math.Ceil(" + toExpression(tr, va, parserArguments, serializerArguments, serialize, suppressPointerAccess) + ")";
-        }
-        // All uppercase names are not fields, but utility methods.
-        else if (vl.getName().equals(vl.getName().toUpperCase())) {
-            StringBuilder sb = new StringBuilder(vl.getName());
-            if (vl.getArgs() != null) {
-                sb.append("(");
-                boolean firstArg = true;
-                for (Term arg : vl.getArgs()) {
-                    if (!firstArg) {
-                        sb.append(", ");
-                    }
-                    sb.append(toExpression(typeReference, arg, parserArguments, serializerArguments, serialize, suppressPointerAccess));
-                    firstArg = false;
-                }
-                sb.append(")");
-            }
-            if (vl.getIndex() != VariableLiteral.NO_INDEX) {
-                sb.append("[").append(vl.getIndex()).append("]");
-            }
-            return sb.toString() + ((vl.getChild() != null) ?
-                "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
-        }
-        // If the current property references a discriminator value, we have to serialize it differently.
-        else if ((getFieldForNameFromCurrentOrParent(vl.getName()) != null) && (getFieldForNameFromCurrentOrParent(vl.getName()) instanceof DiscriminatorField)) {
-            final DiscriminatorField discriminatorField = (DiscriminatorField) getFieldForNameFromCurrentOrParent(vl.getName());
-            System.out.println(discriminatorField);
-        }
-        // If the current property references a parserArguments property and that is a discriminator property, we also have to serialize it differently..
-        else if ((vl.getChild() != null) && (getTypeReferenceForProperty(((ComplexTypeDefinition) getThisTypeDefinition()), vl.getName()) != null)) {
-            final Optional<TypeReference> typeReferenceForProperty = getTypeReferenceForProperty(((ComplexTypeDefinition) getThisTypeDefinition()), vl.getName());
-            if(typeReferenceForProperty.isPresent() && typeReferenceForProperty.get() instanceof ComplexTypeReference) {
-                final TypeReference complexTypeReference = typeReferenceForProperty.get();
-                TypeDefinition typeDefinition = getTypeDefinitionForTypeReference(complexTypeReference);
-                if(typeDefinition instanceof ComplexTypeDefinition) {
-                    ComplexTypeDefinition complexTypeDefinition = (ComplexTypeDefinition) typeDefinition;
-                    String childProperty = vl.getChild().getName();
-                    final Optional<Field> matchingDiscriminatorField = complexTypeDefinition.getFields().stream().filter(field -> (field instanceof DiscriminatorField) && ((DiscriminatorField) field).getName().equals(childProperty)).findFirst();
-                    if(matchingDiscriminatorField.isPresent()) {
-                        return "Cast" + getLanguageTypeNameForTypeReference(complexTypeReference) + "(" + vl.getName() + ")." + StringUtils.capitalize(childProperty) + "()";
-                    }
-                }
-            }
-        }
-        // If the current term references a serialization argument, handle it differently (don't prefix it with "m.")
-        else if((serializerArguments != null) && Arrays.stream(serializerArguments).anyMatch(argument -> argument.getName().equals(vl.getName()))) {
-            return vl.getName() + ((vl.getChild() != null) ?
-                "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
-        }
-        return (serialize ? "m." + StringUtils.capitalize(vl.getName()) : vl.getName()) + ((vl.getChild() != null) ?
-            "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
-    }
-
-    public String getSizeInBits(ComplexTypeDefinition complexTypeDefinition, Argument[] parserArguments) {
-        int sizeInBits = 0;
-        StringBuilder sb = new StringBuilder("");
-        for (Field field : complexTypeDefinition.getFields()) {
-            if(field instanceof ArrayField) {
-                ArrayField arrayField = (ArrayField) field;
-                final SimpleTypeReference type = (SimpleTypeReference) arrayField.getType();
-                switch (arrayField.getLoopType()) {
-                    case COUNT:
-                        sb.append("(").append(toTypedSerializationExpression(type, arrayField.getLoopExpression(), parserArguments)).append(" * ").append(type.getSizeInBits()).append(") + ");
-                        break;
-                    case LENGTH:
-                        sb.append("(").append(toTypedSerializationExpression(type, arrayField.getLoopExpression(), parserArguments)).append(" * 8) + ");
-                        break;
-                    case TERMINATED:
-                        // No terminated.
-                        break;
-                }
-            } else if(field instanceof TypedField) {
-                TypedField typedField = (TypedField) field;
-                final TypeReference type = typedField.getType();
-                if(field instanceof ManualField) {
-                    ManualField manualField = (ManualField) field;
-                    sb.append("(").append(toSerializationExpression(manualField, manualField.getLengthExpression(), parserArguments)).append(") + ");
-                }
-                else if(type instanceof SimpleTypeReference) {
-                    SimpleTypeReference simpleTypeReference = (SimpleTypeReference) type;
-                    sizeInBits += simpleTypeReference.getSizeInBits();
-                } else {
-                    // No ComplexTypeReference supported.
-                }
-            }
-        }
-        return sb.toString() + sizeInBits;
-    }
-
-    public String escapeValue(TypeReference typeReference, String valueString) {
-        if(valueString == null) {
-            return null;
-        }
-        if(typeReference instanceof SimpleTypeReference) {
-            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
-            switch (simpleTypeReference.getBaseType()) {
-                case UINT:
-                case INT:
-                    // If it's a one character string and is numeric, output it as char.
-                    if(!NumberUtils.isParsable(valueString) && (valueString.length() == 1)) {
-                        return "'" + valueString + "'";
-                    }
-                    break;
-                case STRING:
-                    return "\"" + valueString + "\"";
-            }
-        }
-        return valueString;
-    }
-
-    public String escapeEnumValue(TypeReference typeReference, String valueString) {
-        // Currently the only case in which here complex type references are used are when referencing enum constants.
-        if (typeReference instanceof ComplexTypeReference) {
-            // C doesn't like NULL values for enums, so we have to return something else (we'll treat -1 as NULL)
-            if ("null".equals(valueString)) {
-                return "0";
-            }
-            String typeName = valueString.substring(0, valueString.indexOf('.'));
-            String constantName = valueString.substring(valueString.indexOf('.') + 1);
-            return typeName + "_" + constantName;
-        } else {
-            return escapeValue(typeReference, valueString);
-        }
-    }
-
-    public Collection<EnumValue> getUniqueEnumValues(EnumValue[] enumValues) {
-        Map<String, EnumValue> filteredEnumValues = new TreeMap<>();
-        for (EnumValue enumValue : enumValues) {
-            if (!filteredEnumValues.containsKey(enumValue.getValue())) {
-                filteredEnumValues.put(enumValue.getValue(), enumValue);
-            }
-        }
-        return filteredEnumValues.values();
-    }
-
-    public List<String> getRequiredImports() {
-        ComplexTypeDefinition complexTypeDefinition = (ComplexTypeDefinition) getThisTypeDefinition();
-        List<String> imports = new ArrayList<>();
-
-        if(complexTypeDefinition.getAllPropertyFields().stream().anyMatch(field -> isArrayField(field) && getLanguageTypeNameForField(field).equals("int8"))) {
-            imports.add("\"encoding/base64\"");
-        }
-
-        imports.add("\"encoding/xml\"");
-
-        // For "Fields with complex type", constant, typeSwitch,  fields: "errors"
-        if(!complexTypeDefinition.getFields().isEmpty()) {
-            imports.add("\"errors\"");
-        }
-
-        imports.add("\"io\"");
-
-        // At least one reserved field or simple field with complex type
-        if(complexTypeDefinition.getFields().stream().anyMatch(field ->
-            (field instanceof ReservedField))) {
-            imports.add("log \"github.com/sirupsen/logrus\"");
-        }
-
-        // For CEIL functions: "math"
-/*        if(complexTypeDefinition.getFields().stream().anyMatch(field ->
-            FieldUtils.contains(field, "CEIL"))) {
-            imports.add("\"math\"");
-        }*/
-
-        imports.add("\"github.com/apache/plc4x/plc4go/internal/plc4go/utils\"");
-
-        // For Constant field: "strconv"
-        if(complexTypeDefinition.getFields().stream().anyMatch(field ->
-            (field instanceof ConstField))/* || complexTypeDefinition.getAllPropertyFields().stream().anyMatch(
-                propertyField -> isSimpleField(propertyField))*/) {
-            imports.add("\"strconv\"");
-        }
-
-        if(isDiscriminatedParentTypeDefinition()) {
-            imports.add("\"reflect\"");
-            imports.add("\"strings\"");
-        }
-
-        return imports;
-    }
-
-    public List<String> getRequiredImportsForDataIo() {
-        DataIoTypeDefinition dataIo = (DataIoTypeDefinition) getThisTypeDefinition();
-
-        List<String> imports = new ArrayList<>();
-
-        imports.add("\"errors\"");
-        imports.add("\"github.com/apache/plc4x/plc4go/internal/plc4go/model/values\"");
-        imports.add("\"github.com/apache/plc4x/plc4go/internal/plc4go/utils\"");
-        imports.add("api \"github.com/apache/plc4x/plc4go/pkg/plc4go/values\"");
-
-        if(dataIo.getSwitchField().getCases().stream().anyMatch(typeCase ->
-            (typeCase.getName().equals("TIME_OF_DAY") && hasFieldsWithNames(typeCase.getFields(), "hour", "minutes", "seconds")) ||
-                (typeCase.getName().equals("DATE") && hasFieldsWithNames(typeCase.getFields(), "year", "month", "day")) ||
-                (typeCase.getName().equals("DATE_AND_TIME") && hasFieldsWithNames(typeCase.getFields(), "year", "month", "day", "hour", "minutes", "seconds")))) {
-            imports.add("\"time\"");
-        }
-        return imports;
-    }
-
-    public String getVariableName(Field field) {
-        if(!(field instanceof NamedField)) {
-            return "_";
-        }
-        NamedField namedField = (NamedField) field;
-
-        String name = null;
-        for (Field curField : ((ComplexTypeDefinition) getThisTypeDefinition()).getFields()) {
-            if(curField == field) {
-                name = namedField.getName();
-            } else if(name != null) {
-                if(curField instanceof ArrayField) {
-                    ArrayField arrayField = (ArrayField) curField;
-                    if(arrayField.getLoopExpression().contains(name)) {
-                        return name;
-                    }
-                } else if(curField instanceof ChecksumField) {
-                    ChecksumField checksumField = (ChecksumField) curField;
-                    if(checksumField.getChecksumExpression().contains(name)) {
-                        return name;
-                    }
-                } else if(curField instanceof ImplicitField) {
-                    ImplicitField implicitField = (ImplicitField) curField;
-                    if(implicitField.getSerializeExpression().contains(name)) {
-                        return name;
-                    }
-                } else if(curField instanceof ManualArrayField) {
-                    ManualArrayField manualArrayField = (ManualArrayField) curField;
-                    if(manualArrayField.getLengthExpression().contains(name)) {
-                        return name;
-                    }
-                    if(manualArrayField.getLoopExpression().contains(name)) {
-                        return name;
-                    }
-                    if(manualArrayField.getParseExpression().contains(name)) {
-                        return name;
-                    }
-                    if(manualArrayField.getSerializeExpression().contains(name)) {
-                        return name;
-                    }
-                } else if(curField instanceof ManualField) {
-                    ManualField manualField = (ManualField) curField;
-                    if(manualField.getLengthExpression().contains(name)) {
-                        return name;
-                    }
-                    if(manualField.getParseExpression().contains(name)) {
-                        return name;
-                    }
-                    if(manualField.getSerializeExpression().contains(name)) {
-                        return name;
-                    }
-                } else if(curField instanceof OptionalField) {
-                    OptionalField optionalField = (OptionalField) curField;
-                    if(optionalField.getConditionExpression().contains(name)) {
-                        return name;
-                    }
-                } else if(curField instanceof SwitchField) {
-                    SwitchField switchField = (SwitchField) curField;
-                    for (Term discriminatorExpression : switchField.getDiscriminatorExpressions()) {
-                        if(discriminatorExpression.contains(name)) {
-                            return name;
-                        }
-                    }
-                    for (DiscriminatedComplexTypeDefinition curCase : switchField.getCases()) {
-                        for (Argument parserArgument : curCase.getParserArguments()) {
-                            if(parserArgument.getName().equals(name)) {
-                                return name;
-                            }
-                        }
-                    }
-                } else if(curField instanceof VirtualField) {
-                    VirtualField virtualField = (VirtualField) curField;
-                    if(virtualField.getValueExpression().contains(name)) {
-                        return name;
-                    }
-                }
-                if(curField.getParams() != null) {
-                    for (Term param : curField.getParams()) {
-                        if(param.contains(name)) {
-                            return name;
-                        }
-                    }
-                }
-            }
-        }
-
-        return "_";
-    }
-
-    public boolean needsVariable(ArrayField field, String variableName, boolean serialization) {
-        if(!serialization) {
-            if (field.getLoopExpression().contains(variableName)) {
-                return true;
-            }
-        }
-        if((field.getParams() != null) && (field.getParams().length > 0)){
-            for (Term param : field.getParams()) {
-                if(param.contains(variableName)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Right now only the ARRAY_SIZE_IN_BYTES requires helpers to be generated.
-     * Also right now only the Modbus protocol requires this and here the referenced
-     * properties are all also members of the current complex type,
-     * so we'll simplify things here for now.
-     *
-     * @param functionName name of the
-     * @return
-     */
-    public Map<String, String> requiresHelperFunctions(String functionName) {
-        Map<String, String> result = new HashMap<>();
-        boolean usesFunction = false;
-        // As the ARRAY_SIZE_IN_BYTES only applies to ArrayFields, search for these
-        for (Field curField : ((ComplexTypeDefinition) getThisTypeDefinition()).getFields()) {
-            if(curField instanceof ArrayField) {
-                ArrayField arrayField = (ArrayField) curField;
-                if(arrayField.getLoopExpression().contains(functionName)) {
-                    usesFunction = true;
-                }
-                result.put(arrayField.getName(), getLanguageTypeNameForField(arrayField));
-            } else if(curField instanceof ImplicitField) {
-                ImplicitField implicitField = (ImplicitField) curField;
-                if(implicitField.getSerializeExpression().contains(functionName)) {
-                    usesFunction = true;
-                }
-            }
-        }
-        if(usesFunction) {
-            return result;
-        } else {
-            return Collections.emptyMap();
-        }
-    }
-
-    public boolean requiresStartPosAndCurPos() {
-        if(getThisTypeDefinition() instanceof ComplexTypeDefinition) {
-            for (Field curField : ((ComplexTypeDefinition) getThisTypeDefinition()).getFields()) {
-                if (requiresVariable(curField, "curPos")) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    public boolean requiresVariable(Field curField, String variable) {
-        if(curField instanceof ArrayField) {
-            ArrayField arrayField = (ArrayField) curField;
-            if(arrayField.getLoopExpression().contains(variable)) {
-                return true;
-            }
-        } else if(curField instanceof OptionalField) {
-            OptionalField optionalField = (OptionalField) curField;
-            if(optionalField.getConditionExpression().contains(variable)) {
-                return true;
-            }
-        }
-        if(curField.getParams() != null) {
-            for (Term paramTerm : curField.getParams()) {
-                if (paramTerm.contains(variable)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    public Term findTerm(Term baseTerm, String name) {
-        if(baseTerm instanceof VariableLiteral) {
-            VariableLiteral variableLiteral = (VariableLiteral) baseTerm;
-            if(variableLiteral.getName().equals(name)) {
-                return variableLiteral;
-            }
-            if(variableLiteral.getChild() != null) {
-                Term found = findTerm(variableLiteral.getChild(), name);
-                if(found != null) {
-                    return found;
-                }
-            }
-            for (Term arg : variableLiteral.getArgs()) {
-                Term found = findTerm(arg, name);
-                if(found != null) {
-                    return found;
-                }
-            }
-        } else if(baseTerm instanceof UnaryTerm) {
-            UnaryTerm unaryTerm = (UnaryTerm) baseTerm;
-            Term found = findTerm(unaryTerm.getA(), name);
-            if(found != null) {
-                return found;
-            }
-        } else if(baseTerm instanceof BinaryTerm) {
-            BinaryTerm binaryTerm = (BinaryTerm) baseTerm;
-            Term found = findTerm(binaryTerm.getA(), name);
-            if(found != null) {
-                return found;
-            }
-            found = findTerm(binaryTerm.getB(), name);
-            if(found != null) {
-                return found;
-            }
-        } else if(baseTerm instanceof TernaryTerm) {
-            TernaryTerm ternaryTerm = (TernaryTerm) baseTerm;
-            Term found = findTerm(ternaryTerm.getA(), name);
-            if(found != null) {
-                return found;
-            }
-            found = findTerm(ternaryTerm.getB(), name);
-            if(found != null) {
-                return found;
-            }
-            found = findTerm(ternaryTerm.getC(), name);
-            if(found != null) {
-                return found;
-            }
-        }
-        return null;
-    }
-
-}
diff --git a/build-utils/language-cs/src/main/resources/templates/cs/data-io-template.ftlh b/build-utils/language-cs/src/main/resources/templates/cs/data-io-template.ftlh
deleted file mode 100644
index ae9c8df..0000000
--- a/build-utils/language-cs/src/main/resources/templates/cs/data-io-template.ftlh
+++ /dev/null
@@ -1,207 +0,0 @@
-<#--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
--->
-<#-- Prevent freemarker from escaping stuff -->
-<#outputformat "undefined">
-<#-- Declare the name and type of variables passed in to the template -->
-<#-- @ftlvariable name="languageName" type="java.lang.String" -->
-<#-- @ftlvariable name="protocolName" type="java.lang.String" -->
-<#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
-<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.cs.CsLanguageTemplateHelper" -->
-<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
-<#-- Declare the name and type of variables declared locally inside the template -->
-<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
-<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
-<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
-<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
-<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
-<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
-<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
-<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
-<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
-<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
-<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
-<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
-<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
-<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
-<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
-<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
-${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/model/${type.name}.cs
-//
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-//
-
-using System;
-using System.Collections.Generic;
-using System.Text;
-using org.apache.plc4net.api.value;
-using org.apache.plc4net.spi.generation;
-using org.apache.plc4net.spi.model.values;
-
-namespace org.apache.plc4net.drivers.${protocolName?replace("-", "")}.${outputFlavor?replace("-", "")}.model
-{
-
-    public class ${type.name}
-    {
-
-        public IPlcValue Parse(ReadBuffer io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>)
-        {
-    <#list type.switchField.cases as case>
-            if (<#if case.discriminatorValues?has_content><#list case.discriminatorValues as discriminatorValue>${helper.toParseExpression(null, type.switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)} == <#if helper.discriminatorValueNeedsStringEqualityCheck(type.switchField.discriminatorExpressions[discriminatorValue?index])>"${discriminatorValue}"<#else>${discriminatorValue}</#if><#sep> && </#sep></#list></#if>) { // ${case.name}
-        <#assign valueDefined=false>
-        <#if case.name == "Struct">
-                var internalMap = new Dictionary<string, IPlcValue>();
-            <#assign valueDefined=true>
-        </#if>
-        <#list case.fields as field>
-            <#switch field.typeName>
-                <#case "array">
-                    <#assign arrayField = field>
-
-                // Array Field (${field.name});
-                var ${arrayField.name} = new List<IPlcValue>();
-                for (int i = 0; i < ${helper.toParseExpression(null, field.loopExpression, type.parserArguments)}; i++) {
-                    var internalItem = <#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type)}<#else>Complex type array in data-io parsing currently not implemented</#if>;
-                    ${field.name}.Add(new ${helper.getPlcValueTypeForTypeReference(field.type)}(internalItem));
-                }
-                    <#if field.name == "value">
-                        <#assign valueDefined=true>
-                    </#if>
-                    <#break>
-                <#case "manual">
-                    <#assign manualArrayField = field>
-
-                // Manual Field (${field.name})
-                var ${field.name} = ${helper.toParseExpression(field, field.parseExpression, type.parserArguments)};
-                    <#if field.name == "value">
-                        <#assign valueDefined=true>
-                    </#if>
-                    <#break>
-                <#case "reserved">
-                    <#assign reservedField = field>
-
-                // Reserved Field (Just skip the bits)
-                ${helper.getReadBufferReadMethodCall(field.type)};
-                    <#break>
-                <#case "simple">
-                    <#assign simpleField = field>
-
-                // Simple Field (${field.name})
-                var ${field.name} = <#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name}Parse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>;
-                    <#if case.name == "Struct">
-                internalMap["${case.name}"] = new ${helper.getPlcValueTypeForTypeReference(field.type)}(${field.name});
-                    </#if>
-                    <#assign valueDefined=true>
-                    <#break>
-            </#switch>
-        </#list>
-        <#if valueDefined>
-
-            <#switch case.name>
-                <#case "TIME_OF_DAY">
-                    <#if helper.hasFieldsWithNames(case.fields, "hour", "minutes", "seconds")>
-                var value = new DateTime(0,0,0, hour, minutes, seconds);
-                    </#if>
-                return new PlcTIME_OF_DAY(value);
-                    <#break>
-                <#case "DATE">
-                    <#if helper.hasFieldsWithNames(case.fields, "year", "month", "day")>
-                var value = new DateTime(year, month, day, 0, 0, 0);
-                    </#if>
-                return new PlcDATE(value);
-                    <#break>
-                <#case "DATE_AND_TIME">
-                    <#if helper.hasFieldsWithNames(case.fields, "year", "month", "day", "hour", "minutes", "seconds")>
-                var value = new DateTime(year, month, day, hour, minutes, seconds);
-                    </#if>
-                return new PlcDATE_AND_TIME(value);
-                    <#break>
-                <#case "Struct">
-                return new PlcStruct(internalMap);
-                    <#break>
-                <#case "List">
-                return new PlcList(value);
-                    <#break>
-                <#default>
-                return new Plc${case.name}(value);
-            </#switch>
-        </#if>
-            } <#sep>else
-    </#list>
-
-            return null;
-        }
-
-        public void Serialize(WriteBuffer io, IPlcValue value<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>)
-        {
-    <#list type.switchField.cases as case>
-            if (<#if case.discriminatorValues?has_content><#list case.discriminatorValues as discriminatorValue>${helper.toParseExpression(null, type.switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)} == <#if helper.discriminatorValueNeedsStringEqualityCheck(type.switchField.discriminatorExpressions[discriminatorValue?index])>"${discriminatorValue}"<#else>${discriminatorValue}</#if><#sep> && </#sep></#list></#if>) { // ${case.name}
-        <#list case.fields as field>
-            <#switch field.typeName>
-                <#case "array">
-                    <#assign arrayField = field>
-
-                // Array Field (${field.name})
-                for (int i = 0; i < ${helper.toSerializationExpression(null, field.loopExpression, type.parserArguments)}; i++) {
-                    <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getWriteBufferWriteMethodCall(arrayField.type, arrayField.name + ".GetIndex(i).Get" + helper.getLanguageTypeNameForTypeReference(arrayField.type)?cap_first + "()")}<#else>Complex type array in data-io serialization currently not implemented</#if>;
-                }
-                    <#break>
-                <#case "manual">
-                    <#assign manualField = field>
-
-                // Manual Field (${field.name})
-                ${helper.toSerializationExpression(field, manualField.serializeExpression, type.parserArguments)};
-                    <#break>
-                <#case "reserved">
-                    <#assign reservedField = field>
-
-                // Reserved Field (Just skip the bytes)
-                ${helper.getWriteBufferWriteMethodCall(field.type, helper.getReservedValue(field))};
-                    <#break>
-                <#case "simple">
-                    <#assign simpleField = field>
-
-                // Simple Field (${field.name})
-                <#if helper.isSimpleTypeReference(field.type)>${helper.getWriteBufferWriteMethodCall(field.type, "value.Get" + helper.getLanguageTypeNameForTypeReference(field.type)?cap_first + "()")}<#else>${field.type.name}Serialize(io, <#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments [...]
-                    <#break>
-            </#switch>
-        </#list>
-            } <#sep>else
-    </#list>
-        }
-
-    }
-
-}
-
-</#outputformat>
diff --git a/build-utils/language-cs/src/main/resources/templates/cs/model-template.ftlh b/build-utils/language-cs/src/main/resources/templates/cs/model-template.ftlh
deleted file mode 100644
index 795a979..0000000
--- a/build-utils/language-cs/src/main/resources/templates/cs/model-template.ftlh
+++ /dev/null
@@ -1,134 +0,0 @@
-<#--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
--->
-<#-- Prevent freemarker from escaping stuff -->
-<#outputformat "undefined">
-<#-- Declare the name and type of variables passed in to the template -->
-<#-- @ftlvariable name="languageName" type="java.lang.String" -->
-<#-- @ftlvariable name="protocolName" type="java.lang.String" -->
-<#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
-<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.cs.CsLanguageTemplateHelper" -->
-<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
-<#-- Declare the name and type of variables declared locally inside the template -->
-<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
-<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
-<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
-<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
-<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
-<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
-<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
-<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
-<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
-<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
-<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
-<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
-<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
-<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
-<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
-<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
-${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/model/${type.name}.cs
-//
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-//
-
-namespace org.apache.plc4net.drivers.${protocolName?replace("-", "")}.${outputFlavor?replace("-", "")}.model
-{
-
-    public<#if helper.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${type.name}<#if type.parentType??> : ${type.parentType.name}</#if>
-    {
-    <#--
-        If this is a discriminated child type, we need to generate methods for accessing it's discriminator
-        values, as if they were normal java properties.
-    -->
-    <#if helper.isDiscriminatedChildTypeDefinition()>
-        <#assign discriminatedChildType = type>
-
-        <#-- @ftlvariable name="discriminatedChildType" type="org.apache.plc4x.plugins.codegenerator.types.definitions.DiscriminatedComplexTypeDefinition" -->
-        // Accessors for discriminator values.
-        <#list helper.getDiscriminatorValues(discriminatedChildType) as discriminatorName, discriminatorValue>
-        <#-- If the discriminator name matches that of another field, suppress the methods generation -->
-            <#if !helper.isNonDiscriminatorField(discriminatorName)>
-        public override ${helper.getLanguageTypeNameForTypeReference(helper.getDiscriminatorTypes()[discriminatorName])} Get${discriminatorName?cap_first}() {
-            return <#if discriminatorValue??>${discriminatorValue}<#else>${helper.getNullValueForTypeReference(helper.getDiscriminatorTypes()[discriminatorName])}</#if>;
-        }
-            </#if>
-        </#list>
-    </#if>
-    <#--
-        If this is a discriminated parent type, we need to generate the abstract methods for accessing it's
-        discriminator values instead.
-    -->
-    <#if helper.isDiscriminatedParentTypeDefinition()>
-        <#assign discriminatedParentType = type>
-
-    <#-- @ftlvariable name="discriminatedParentType" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
-        // Abstract accessors for discriminator values.
-        <#list helper.getDiscriminatorTypes() as discriminatorName, discriminatorType>
-        <#-- If the discriminator name matches that of another field, suppress the methods generation -->
-            <#if !helper.isNonDiscriminatorField(discriminatorName)>
-        public abstract ${helper.getLanguageTypeNameForTypeReference(discriminatorType)} Get${discriminatorName?cap_first}();
-            </#if>
-        </#list>
-    </#if>
-    <#-- If the current type contains "const" fields, generate some java constants for holing their values -->
-    <#if type.constFields?has_content>
-
-        // Constant values.
-        <#list type.constFields as field>
-        public const ${helper.getLanguageTypeNameForField(field)} ${field.name?upper_case} = ${field.referenceValue};
-        </#list>
-    </#if>
-    <#-- Prpoerty fields are fields that require a property in the pojo -->
-    <#if type.propertyFields?has_content>
-
-        // Properties.
-        <#list type.propertyFields as field>
-        public ${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name?cap_first} { get; }
-        </#list>
-    </#if>
-
-    <#-- getAllPropertyFields() returns not only the property fields of this type but also of it's parents -->
-        public ${type.name}(<#list type.getAllPropertyFields() as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>)
-    <#if type.getParentPropertyFields()?has_content>
-            : base(<#list type.getParentPropertyFields() as field>${field.name}<#sep>, </#sep></#list>)
-    </#if>
-        {
-    <#list type.propertyFields as field>
-            ${field.name?cap_first} = ${field.name};
-    </#list>
-        }
-
-    }
-
-}
-</#outputformat>
\ No newline at end of file
diff --git a/build-utils/language-cs/pom.xml b/code-generation/language-cs/pom.xml
similarity index 75%
rename from build-utils/language-cs/pom.xml
rename to code-generation/language-cs/pom.xml
index 2a02405..b0e951d 100644
--- a/build-utils/language-cs/pom.xml
+++ b/code-generation/language-cs/pom.xml
@@ -19,25 +19,25 @@
   -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
-  <modelVersion>4.0.0</modelVersion>
+  <modelVersion>4.0.0</modelVersion><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>8</source><target>8</target></configuration></plugin></plugins></build>
 
   <parent>
     <groupId>org.apache.plc4x</groupId>
-    <artifactId>plc4x-build-utils</artifactId>
-    <version>0.8.0-SNAPSHOT</version>
+    <artifactId>plc4x-code-generation</artifactId>
+    <version>0.10.0-SNAPSHOT</version>
   </parent>
 
-  <artifactId>plc4x-build-utils-language-cs</artifactId>
+  <artifactId>plc4x-code-generation-language-cs</artifactId>
 
-  <name>PLC4X: Build Utils: Language: C#</name>
+  <name>Code-Generation: Language: C#</name>
   <description>Code generation template for generating C# code</description>
 
   <dependencies>
     <!-- We are using the Freemarker module to generate Java code -->
     <dependency>
       <groupId>org.apache.plc4x</groupId>
-      <artifactId>plc4x-build-utils-language-base-freemarker</artifactId>
-      <version>0.8.0-SNAPSHOT</version>
+      <artifactId>plc4x-code-generation-language-base-freemarker</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
     </dependency>
 
     <dependency>
diff --git a/build-utils/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageOutput.java b/code-generation/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageOutput.java
similarity index 89%
rename from build-utils/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageOutput.java
rename to code-generation/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageOutput.java
index 9009615..71f8a4a 100644
--- a/build-utils/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageOutput.java
+++ b/code-generation/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageOutput.java
@@ -26,10 +26,7 @@ import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerLang
 import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition;
 
 import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 public class CsLanguageOutput extends FreemarkerLanguageOutput {
 
@@ -44,31 +41,36 @@ public class CsLanguageOutput extends FreemarkerLanguageOutput {
     }
 
     @Override
-    protected List<Template> getSpecTemplates(Configuration freemarkerConfiguration) throws IOException {
+    public Set<String> supportedOptions() {
+        return null;
+    }
+
+    @Override
+    protected List<Template> getSpecTemplates(Configuration freemarkerConfiguration) {
         return Collections.emptyList();
     }
 
     @Override
     protected List<Template> getComplexTypeTemplates(Configuration freemarkerConfiguration) throws IOException {
         return Collections.singletonList(
-            freemarkerConfiguration.getTemplate("templates/cs/model-template.ftlh"));
+            freemarkerConfiguration.getTemplate("templates/cs/model-template.cs.ftlh"));
     }
 
     @Override
     protected List<Template> getEnumTypeTemplates(Configuration freemarkerConfiguration) throws IOException {
         return Collections.singletonList(
-            freemarkerConfiguration.getTemplate("templates/cs/enum-template.ftlh"));
+            freemarkerConfiguration.getTemplate("templates/cs/enum-template.cs.ftlh"));
     }
 
     @Override
     protected List<Template> getDataIoTemplates(Configuration freemarkerConfiguration) throws IOException {
         return Collections.singletonList(
-            freemarkerConfiguration.getTemplate("templates/cs/data-io-template.ftlh"));
+            freemarkerConfiguration.getTemplate("templates/cs/data-io-template.cs.ftlh"));
     }
 
     @Override
-    protected FreemarkerLanguageTemplateHelper getHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types) {
-        return new CsLanguageTemplateHelper(thisType, protocolName, flavorName, types);
+    protected FreemarkerLanguageTemplateHelper getHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types, Map<String, String> options) {
+        return new CsLanguageTemplateHelper(thisType, protocolName, flavorName, types, options);
     }
 
 }
diff --git a/code-generation/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageTemplateHelper.java b/code-generation/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageTemplateHelper.java
new file mode 100644
index 0000000..5bbb339
--- /dev/null
+++ b/code-generation/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageTemplateHelper.java
@@ -0,0 +1,1201 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+package org.apache.plc4x.language.cs;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.commons.text.WordUtils;
+import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.BaseFreemarkerLanguageTemplateHelper;
+import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerException;
+import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer;
+import org.apache.plc4x.plugins.codegenerator.types.definitions.*;
+import org.apache.plc4x.plugins.codegenerator.types.fields.*;
+import org.apache.plc4x.plugins.codegenerator.types.references.*;
+import org.apache.plc4x.plugins.codegenerator.types.terms.*;
+
+import java.util.*;
+import java.util.function.Function;
+
+@SuppressWarnings({"unused", "WeakerAccess"})
+public class CsLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelper {
+
+    private final Map<String, String> options;
+
+    public CsLanguageTemplateHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types,
+                                      Map<String, String> options) {
+        super(thisType, protocolName, flavorName, types);
+        this.options = options;
+    }
+
+    public String fileName(String protocolName, String languageName, String languageFlavorName) {
+        return "drivers." + String.join("", protocolName.split("\\-")) + "." +
+            String.join("", languageFlavorName.split("\\-"));
+    }
+
+    public String packageName() {
+        return packageName(protocolName, "cs", flavorName);
+    }
+
+    public String packageName(String protocolName, String languageName, String languageFlavorName) {
+        return Optional.ofNullable(options.get("package")).orElseGet(() ->
+            "org.apache.plc4x." + String.join("", languageName.split("-")) + "." +
+                String.join("", protocolName.split("-")) + "." +
+                String.join("", languageFlavorName.split("-")));
+    }
+
+    @Override
+    public String getLanguageTypeNameForField(Field field) {
+        // If the referenced type is a DataIo type, the value is of type PlcValue.
+        if (field.isPropertyField()) {
+            PropertyField propertyField = field.asPropertyField().orElseThrow(IllegalStateException::new);
+            if (propertyField.getType().isComplexTypeReference()) {
+                ComplexTypeReference complexTypeReference = propertyField.getType().asComplexTypeReference().orElseThrow(IllegalStateException::new);
+                final TypeDefinition typeDefinition = getTypeDefinitions().get(complexTypeReference.getName());
+                if (typeDefinition instanceof DataIoTypeDefinition) {
+                    return "PlcValue";
+                }
+            }
+        }
+        return getLanguageTypeNameForTypeReference(((TypedField) field).getType());
+    }
+
+    @Override
+    public String getLanguageTypeNameForTypeReference(TypeReference typeReference) {
+        Objects.requireNonNull(typeReference);
+        if (!(typeReference instanceof SimpleTypeReference)) {
+            return ((ComplexTypeReference) typeReference).getName();
+        }
+        SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
+        switch (simpleTypeReference.getBaseType()) {
+            case BIT:
+                return "bool";
+            case BYTE:
+                return "byte";
+            case UINT:
+                IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                if (unsignedIntegerTypeReference.getSizeInBits() <= 8) {
+                    return "byte";
+                }
+                if (unsignedIntegerTypeReference.getSizeInBits() <= 16) {
+                    return "ushort";
+                }
+                if (unsignedIntegerTypeReference.getSizeInBits() <= 32) {
+                    return "uint";
+                }
+                if (unsignedIntegerTypeReference.getSizeInBits() <= 64) {
+                    return "ulong";
+                }
+                throw new RuntimeException("Unsupported simple type");
+            case INT:
+                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                if (integerTypeReference.getSizeInBits() <= 8) {
+                    return "sbyte";
+                }
+                if (integerTypeReference.getSizeInBits() <= 16) {
+                    return "short";
+                }
+                if (integerTypeReference.getSizeInBits() <= 32) {
+                    return "int";
+                }
+                if (integerTypeReference.getSizeInBits() <= 64) {
+                    return "long";
+                }
+                throw new RuntimeException("Unsupported simple type");
+            case FLOAT:
+            case UFLOAT:
+                FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+                int sizeInBits = floatTypeReference.getSizeInBits();
+                if (sizeInBits <= 32) {
+                    return "float";
+                }
+                if (sizeInBits <= 64) {
+                    return "double";
+                }
+                throw new RuntimeException("Unsupported simple type");
+            case STRING:
+            case VSTRING:
+                return "string";
+            case TIME:
+                return "time";
+            case DATE:
+                return "date";
+            case DATETIME:
+                return "datetime2";
+
+        }
+        throw new RuntimeException("Unsupported simple type");
+    }
+
+    public String getPlcValueTypeForTypeReference(TypeReference typeReference) {
+        if (!(typeReference instanceof SimpleTypeReference)) {
+            return "PlcStruct";
+        }
+        SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
+        switch (simpleTypeReference.getBaseType()) {
+            case BIT:
+                return "PlcBOOL";
+            case BYTE:
+                return "PlcBYTE";
+            case UINT:
+                IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                if (unsignedIntegerTypeReference.getSizeInBits() <= 8) {
+                    return "PlcUSINT";
+                }
+                if (unsignedIntegerTypeReference.getSizeInBits() <= 16) {
+                    return "PlcUINT";
+                }
+                if (unsignedIntegerTypeReference.getSizeInBits() <= 32) {
+                    return "PlcUDINT";
+                }
+                if (unsignedIntegerTypeReference.getSizeInBits() <= 64) {
+                    return "PlcULINT";
+                }
+            case INT:
+                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                if (integerTypeReference.getSizeInBits() <= 8) {
+                    return "PlcSINT";
+                }
+                if (integerTypeReference.getSizeInBits() <= 16) {
+                    return "PlcINT";
+                }
+                if (integerTypeReference.getSizeInBits() <= 32) {
+                    return "PlcDINT";
+                }
+                if (integerTypeReference.getSizeInBits() <= 64) {
+                    return "PlcLINT";
+                }
+
+            case FLOAT:
+            case UFLOAT:
+                FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+                int sizeInBits = floatTypeReference.getSizeInBits();
+                if (sizeInBits <= 32) {
+                    return "PlcREAL";
+                }
+                if (sizeInBits <= 64) {
+                    return "PlcLREAL";
+                }
+            case STRING:
+            case VSTRING:
+                return "PlcSTRING";
+            case TIME:
+            case DATE:
+            case DATETIME:
+                return "PlcTIME";
+        }
+        throw new RuntimeException("Unsupported simple type");
+    }
+
+    @Override
+    public String getNullValueForTypeReference(TypeReference typeReference) {
+        if (typeReference instanceof SimpleTypeReference) {
+            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
+            switch (simpleTypeReference.getBaseType()) {
+                case BIT:
+                    return "false";
+                case BYTE:
+                    return "0";
+                case UINT:
+                    IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                    if (unsignedIntegerTypeReference.getSizeInBits() <= 16) {
+                        return "0";
+                    }
+                    if (unsignedIntegerTypeReference.getSizeInBits() <= 32) {
+                        return "0l";
+                    }
+                    return "null";
+                case INT:
+                    IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                    if (integerTypeReference.getSizeInBits() <= 32) {
+                        return "0";
+                    }
+                    if (integerTypeReference.getSizeInBits() <= 64) {
+                        return "0l";
+                    }
+                    return "null";
+                case FLOAT:
+                    FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+                    int sizeInBits = floatTypeReference.getSizeInBits();
+                    if (sizeInBits <= 32) {
+                        return "0.0f";
+                    }
+                    if (sizeInBits <= 64) {
+                        return "0.0";
+                    }
+                    return "null";
+                case STRING:
+                case VSTRING:
+                    return "null";
+            }
+            throw new FreemarkerException("Unmapped base-type" + simpleTypeReference.getBaseType());
+        } else {
+            return "null";
+        }
+    }
+
+    public int getNumBits(SimpleTypeReference simpleTypeReference) {
+        switch (simpleTypeReference.getBaseType()) {
+            case BIT:
+                return 1;
+            case BYTE:
+                return 8;
+            case UINT:
+            case INT:
+                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                return integerTypeReference.getSizeInBits();
+            case FLOAT:
+                FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+                return floatTypeReference.getSizeInBits();
+            case STRING:
+                StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
+                return stringTypeReference.getSizeInBits();
+            case VSTRING:
+                throw new IllegalArgumentException("getSizeInBits doesn't work for 'vstring' fields");
+            default:
+                return 0;
+        }
+    }
+
+    @Deprecated
+    @Override
+    public String getReadBufferReadMethodCall(SimpleTypeReference simpleTypeReference, String valueString, TypedField field) {
+        return getReadBufferReadMethodCall("", simpleTypeReference, valueString, field);
+    }
+
+    @Deprecated
+    public String getReadBufferReadMethodCall(String logicalName, SimpleTypeReference simpleTypeReference, String valueString, TypedField field) {
+        switch (simpleTypeReference.getBaseType()) {
+            case BIT:
+                return "readBuffer.ReadBit(\"" + logicalName + "\")";
+            case BYTE:
+                return "readBuffer.ReadByte(\"" + logicalName + "\", 8)";
+            case UINT:
+                String unsignedIntegerType;
+                IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                if (unsignedIntegerTypeReference.getSizeInBits() <= 8) {
+                    unsignedIntegerType = "Byte";
+                } else if (unsignedIntegerTypeReference.getSizeInBits() <= 16) {
+                    unsignedIntegerType = "Ushort";
+                } else if (unsignedIntegerTypeReference.getSizeInBits() <= 32) {
+                    unsignedIntegerType = "Uint";
+                } else if (unsignedIntegerTypeReference.getSizeInBits() <= 64) {
+                    unsignedIntegerType = "Ulong";
+                } else {
+                    throw new RuntimeException("Unsupported type");
+                }
+                return "readBuffer.Read" + unsignedIntegerType + "(\"" + logicalName + "\", " + simpleTypeReference.getSizeInBits() + ")";
+            case INT:
+                String integerType;
+                if (simpleTypeReference.getSizeInBits() <= 8) {
+                    integerType = "Sbyte";
+                } else if (simpleTypeReference.getSizeInBits() <= 16) {
+                    integerType = "Short";
+                } else if (simpleTypeReference.getSizeInBits() <= 32) {
+                    integerType = "Int";
+                } else if (simpleTypeReference.getSizeInBits() <= 64) {
+                    integerType = "Long";
+                } else {
+                    throw new RuntimeException("Unsupported type");
+                }
+                return "readBuffer.Read" + integerType + "(\"" + logicalName + "\", " + simpleTypeReference.getSizeInBits() + ")";
+            case FLOAT:
+                String floatType = (simpleTypeReference.getSizeInBits() <= 32) ? "Float" : "Double";
+                return "readBuffer.Read" + floatType + "(\"" + logicalName + "\", " + simpleTypeReference.getSizeInBits() + ")";
+            case STRING:
+            case VSTRING:
+                String stringType = "String";
+                final Term encodingTerm = field.getEncoding().orElse(new DefaultStringLiteral("UTF-8"));
+                if (!(encodingTerm instanceof StringLiteral)) {
+                    throw new RuntimeException("Encoding must be a quoted string value");
+                }
+                String encoding = ((StringLiteral) encodingTerm).getValue();
+                String length = Integer.toString(simpleTypeReference.getSizeInBits());
+                if (simpleTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.VSTRING) {
+                    VstringTypeReference vstringTypeReference = (VstringTypeReference) simpleTypeReference;
+                    length = toParseExpression(field, INT_TYPE_REFERENCE, vstringTypeReference.getLengthExpression(), null);
+                }
+                return "readBuffer.Read" + stringType + "(\"" + logicalName + "\", " + length + ", System.Text.Encoding.GetEncoding(\"" +
+                    encoding + "\"))";
+        }
+        return "";
+    }
+
+    public String getDataReaderCall(TypeReference typeReference) {
+        return getDataReaderCall(typeReference, "enumForValue");
+    }
+
+    public String getDataReaderCall(TypeReference typeReference, String resolverMethod) {
+        if (isEnumTypeReference(typeReference)) {
+            final String languageTypeName = getLanguageTypeNameForTypeReference(typeReference);
+            final SimpleTypeReference enumBaseTypeReference = getEnumBaseTypeReference(typeReference);
+            return "new DataReaderEnumDefault<>(" + languageTypeName + "::" + resolverMethod + ", " + getDataReaderCall(enumBaseTypeReference) + ")";
+        } else if (typeReference.isSimpleTypeReference()) {
+            SimpleTypeReference simpleTypeReference = typeReference.asSimpleTypeReference().orElseThrow(IllegalStateException::new);
+            return getDataReaderCall(simpleTypeReference);
+        } else if (typeReference.isComplexTypeReference()) {
+            StringBuilder paramsString = new StringBuilder();
+            ComplexTypeReference complexTypeReference = typeReference.asComplexTypeReference().orElseThrow(IllegalStateException::new);
+            TypeDefinition typeDefinition = getTypeDefinitionForTypeReference(typeReference);
+            String parserCallString = getLanguageTypeNameForTypeReference(typeReference);
+            if (typeDefinition.isDiscriminatedChildTypeDefinition()) {
+                parserCallString = "(" + getLanguageTypeNameForTypeReference(typeReference) + ") " + typeDefinition.getParentType().getName();
+            }
+            List<Term> paramTerms = complexTypeReference.getParams().orElse(Collections.emptyList());
+            for (int i = 0; i < paramTerms.size(); i++) {
+                Term paramTerm = paramTerms.get(i);
+                final TypeReference argumentType = getArgumentType(complexTypeReference, i);
+                paramsString
+                    .append(", (")
+                    .append(getLanguageTypeNameForTypeReference(argumentType))
+                    .append(") (")
+                    .append(toParseExpression(null, argumentType, paramTerm, null))
+                    .append(")");
+            }
+            return "new DataReaderComplexDefault<>(() -> " + parserCallString + "IO.staticParse(readBuffer" + paramsString + "), readBuffer)";
+        } else {
+            throw new IllegalStateException("What is this type? " + typeReference);
+        }
+    }
+
+    public String getDataReaderCall(SimpleTypeReference simpleTypeReference) {
+        final int sizeInBits = simpleTypeReference.getSizeInBits();
+        switch (simpleTypeReference.getBaseType()) {
+            case BIT:
+                return "readBoolean(readBuffer)";
+            case BYTE:
+                return "readByte(readBuffer, " + sizeInBits + ")";
+            case UINT:
+                if (sizeInBits <= 4) return "readUnsignedByte(readBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 8) return "readUnsignedShort(readBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 16) return "readUnsignedInt(readBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 32) return "readUnsignedLong(readBuffer, " + sizeInBits + ")";
+                return "readUnsignedBigInteger(readBuffer, " + sizeInBits + ")";
+            case INT:
+                if (sizeInBits <= 8) return "readSignedByte(readBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 16) return "readSignedShort(readBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 32) return "readSignedInt(readBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 64) return "readSignedLong(readBuffer, " + sizeInBits + ")";
+                return "readSignedBigInteger(readBuffer, " + sizeInBits + ")";
+            case FLOAT:
+                if (sizeInBits <= 32) return "readFloat(readBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 64) return "readDouble(readBuffer, " + sizeInBits + ")";
+                return "readBigDecimal(readBuffer, " + sizeInBits + ")";
+            case STRING:
+                return "readString(readBuffer, " + sizeInBits + ")";
+            case VSTRING:
+                VstringTypeReference vstringTypeReference = (VstringTypeReference) simpleTypeReference;
+                return "readString(readBuffer, " + toParseExpression(null, INT_TYPE_REFERENCE, vstringTypeReference.getLengthExpression(), null) + ")";
+            case TIME:
+                return "readTime(readBuffer)";
+            case DATE:
+                return "readDate(readBuffer)";
+            case DATETIME:
+                return "readDateTime(readBuffer)";
+            default:
+                throw new UnsupportedOperationException("Unsupported type " + simpleTypeReference.getBaseType());
+        }
+    }
+
+    public String getDataWriterCall(TypeReference typeReference, String fieldName) {
+        if (typeReference.isSimpleTypeReference()) {
+            SimpleTypeReference simpleTypeReference = typeReference.asSimpleTypeReference().orElseThrow(IllegalStateException::new);
+            return getDataWriterCall(simpleTypeReference);
+        } else if (typeReference.isComplexTypeReference()) {
+            return "new DataWriterComplexDefault<>(writeBuffer)";
+        } else {
+            throw new IllegalStateException("What is this type? " + typeReference);
+        }
+    }
+
+    public String getEnumDataWriterCall(TypeReference typeReference, String fieldName, String attributeName) {
+        if (!isEnumTypeReference(typeReference)) {
+            throw new IllegalArgumentException("this method should only be called for enum types");
+        }
+        final String languageTypeName = getLanguageTypeNameForTypeReference(typeReference);
+        SimpleTypeReference outputTypeReference;
+        if ("value".equals(attributeName)) {
+            outputTypeReference = getEnumBaseTypeReference(typeReference);
+        } else {
+            outputTypeReference = getEnumFieldSimpleTypeReference(typeReference, attributeName);
+        }
+        return "new DataWriterEnumDefault<>(" + languageTypeName + "::get" + StringUtils.capitalize(attributeName) + ", " + languageTypeName + "::name, " + getDataWriterCall(outputTypeReference, fieldName) + ")";
+    }
+
+    public String getDataWriterCall(SimpleTypeReference simpleTypeReference) {
+        final int sizeInBits = simpleTypeReference.getSizeInBits();
+        switch (simpleTypeReference.getBaseType()) {
+            case BIT:
+                return "writeBoolean(writeBuffer)";
+            case BYTE:
+                return "writeByte(writeBuffer, " + sizeInBits + ")";
+            case UINT:
+                if (sizeInBits <= 4) return "writeUnsignedByte(writeBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 8) return "writeUnsignedShort(writeBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 16) return "writeUnsignedInt(writeBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 32) return "writeUnsignedLong(writeBuffer, " + sizeInBits + ")";
+                return "writeUnsignedBigInteger(writeBuffer, " + sizeInBits + ")";
+            case INT:
+                if (sizeInBits <= 8) return "writeSignedByte(writeBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 16) return "writeSignedShort(writeBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 32) return "writeSignedInt(writeBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 64) return "writeSignedLong(writeBuffer, " + sizeInBits + ")";
+                return "writeSignedBigInteger(writeBuffer, " + sizeInBits + ")";
+            case FLOAT:
+                if (sizeInBits <= 32) return "writeFloat(writeBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 64) return "writeDouble(writeBuffer, " + sizeInBits + ")";
+                return "writeBigDecimal(writeBuffer, " + sizeInBits + ")";
+            case STRING:
+                return "writeString(writeBuffer, " + sizeInBits + ")";
+            case VSTRING:
+                VstringTypeReference vstringTypeReference = (VstringTypeReference) simpleTypeReference;
+                return "writeString(writeBuffer, " + toParseExpression(null, INT_TYPE_REFERENCE, vstringTypeReference.getLengthExpression(), null) + ")";
+            case TIME:
+                return "writeTime(writeBuffer)";
+            case DATE:
+                return "writeDate(writeBuffer)";
+            case DATETIME:
+                return "writeDateTime(readBuffer)";
+            default:
+                throw new UnsupportedOperationException("Unsupported type " + simpleTypeReference.getBaseType());
+        }
+    }
+
+    @Deprecated
+    @Override
+    public String getWriteBufferWriteMethodCall(SimpleTypeReference simpleTypeReference, String fieldName, TypedField field) {
+        return getWriteBufferWriteMethodCall("", simpleTypeReference, fieldName, field);
+    }
+
+    @Deprecated
+    public String getWriteBufferWriteMethodCall(String logicalName, SimpleTypeReference simpleTypeReference, String fieldName, TypedField field, String... writerArgs) {
+        String writerArgsString = "";
+        if (writerArgs.length > 0) {
+            writerArgsString += ", " + StringUtils.join(writerArgs, ", ");
+        }
+        switch (simpleTypeReference.getBaseType()) {
+            case BIT:
+                return "writeBuffer.WriteBit(\"" + logicalName + "\", " + fieldName + "" + writerArgsString + ")";
+            case BYTE:
+                ByteTypeReference byteTypeReference = (ByteTypeReference) simpleTypeReference;
+                return "writeBuffer.WriteByte(\"" + logicalName + "\", " + fieldName + writerArgsString + ", 8)";
+            case UINT:
+                IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                if (unsignedIntegerTypeReference.getSizeInBits() <= 8) {
+                    return "writeBuffer.WriteByte(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ", (byte) " + fieldName + writerArgsString + ")";
+                }
+                if (unsignedIntegerTypeReference.getSizeInBits() <= 16) {
+                    return "writeBuffer.WriteUshort(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ", (ushort) " + fieldName + writerArgsString + ")";
+                }
+                if (unsignedIntegerTypeReference.getSizeInBits() <= 32) {
+                    return "writeBuffer.WriteUint(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ", (uint) " + fieldName + writerArgsString + ")";
+                }
+                if (unsignedIntegerTypeReference.getSizeInBits() <= 64) {
+                    return "writeBuffer.WriteUlong(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ", (ulong) " + fieldName + writerArgsString + ")";
+                }
+                throw new RuntimeException("Unsupported uint type");
+            case INT:
+                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                if (integerTypeReference.getSizeInBits() <= 8) {
+                    return "writeBuffer.WriteSbyte(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ", (sbyte) " + fieldName + writerArgsString + ")";
+                }
+                if (integerTypeReference.getSizeInBits() <= 16) {
+                    return "writeBuffer.WriteShort(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ", (short) " + fieldName + writerArgsString + ")";
+                }
+                if (integerTypeReference.getSizeInBits() <= 32) {
+                    return "writeBuffer.WriteInt(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ", (int) " + fieldName + writerArgsString + ")";
+                }
+                if (integerTypeReference.getSizeInBits() <= 64) {
+                    return "writeBuffer.WriteLong(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ", (long) " + fieldName + writerArgsString + ")";
+                }
+                throw new RuntimeException("Unsupported int type");
+            case FLOAT:
+            case UFLOAT:
+                FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+                if (floatTypeReference.getSizeInBits() <= 32) {
+                    return "writeBuffer.WriteFloat(\"" + logicalName + "\", " + floatTypeReference.getSizeInBits() + "," + fieldName + writerArgsString + ")";
+                } else if (floatTypeReference.getSizeInBits() <= 64) {
+                    return "writeBuffer.WriteDouble(\"" + logicalName + "\", " + floatTypeReference.getSizeInBits() + "," + fieldName + writerArgsString + ")";
+                } else {
+                    throw new RuntimeException("Unsupported float type");
+                }
+            case STRING:
+            case VSTRING:
+                final Term encodingTerm = field.getEncoding().orElse(new DefaultStringLiteral("UTF-8"));
+                if (!(encodingTerm instanceof StringLiteral)) {
+                    throw new RuntimeException("Encoding must be a quoted string value");
+                }
+                String encoding = ((StringLiteral) encodingTerm).getValue();
+                String length = Integer.toString(simpleTypeReference.getSizeInBits());
+                if (simpleTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.VSTRING) {
+                    VstringTypeReference vstringTypeReference = (VstringTypeReference) simpleTypeReference;
+                    length = toSerializationExpression(field, INT_TYPE_REFERENCE, vstringTypeReference.getLengthExpression(), thisType.getParserArguments().orElse(Collections.emptyList()));
+                }
+                return "writeBuffer.WriteString(\"" + logicalName + "\", " + length + ", \"" +
+                    encoding + "\", (string) " + fieldName + "" + writerArgsString + ")";
+        }
+        throw new FreemarkerException("Unmapped basetype" + simpleTypeReference.getBaseType());
+    }
+
+    public String getReservedValue(ReservedField reservedField) {
+        final String languageTypeName = getLanguageTypeNameForTypeReference(reservedField.getType());
+        if ("BigInteger".equals(languageTypeName)) {
+            return "BigInteger.valueOf(" + reservedField.getReferenceValue() + ")";
+        } else {
+            return "" + reservedField.getReferenceValue();
+        }
+    }
+
+    /**
+     * @param field           this generally only is needed in order to access field attributes such as encoding etc.
+     * @param resultType      the type the resulting expression should have
+     * @param term            the term representing the expression
+     * @param parserArguments any parser arguments, which could be referenced in expressions (Needed for getting the type)
+     * @return Java code which does the things defined in 'term'
+     */
+    public String toParseExpression(Field field, TypeReference resultType, Term term, List<Argument> parserArguments) {
+        Tracer tracer = Tracer.start("toParseExpression");
+        return tracer + toExpression(field, resultType, term, variableLiteral -> tracer.dive("variableExpressionGenerator") + toVariableParseExpression(field, resultType, variableLiteral, parserArguments));
+    }
+
+    /**
+     * @param field               this generally only is needed in order to access field attributes such as encoding etc.
+     * @param resultType          the type the resulting expression should have
+     * @param term                the term representing the expression
+     * @param serializerArguments any serializer arguments, which could be referenced in expressions (Needed for getting the type)
+     * @return Java code which does the things defined in 'term'
+     */
+    public String toSerializationExpression(Field field, TypeReference resultType, Term term, List<Argument> serializerArguments) {
+        Tracer tracer = Tracer.start("toSerializationExpression");
+        return tracer + toExpression(field, resultType, term, variableLiteral -> tracer.dive("variableExpressionGenerator") + toVariableSerializationExpression(field, resultType, variableLiteral, serializerArguments));
+    }
+
+    private String toExpression(Field field, TypeReference resultType, Term term, Function<VariableLiteral, String> variableExpressionGenerator) {
+        Tracer tracer = Tracer.start("toExpression");
+        if (term == null) {
+            return tracer + "";
+        }
+        if (term instanceof Literal) {
+            return toLiteralTermExpression(field, resultType, (Literal) term, variableExpressionGenerator, tracer);
+        } else if (term instanceof UnaryTerm) {
+            return toUnaryTermExpression(field, resultType, (UnaryTerm) term, variableExpressionGenerator, tracer);
+        } else if (term instanceof BinaryTerm) {
+            return toBinaryTermExpression(field, resultType, (BinaryTerm) term, variableExpressionGenerator, tracer);
+        } else if (term instanceof TernaryTerm) {
+            return toTernaryTermExpression(field, resultType, (TernaryTerm) term, variableExpressionGenerator, tracer);
+        } else {
+            throw new RuntimeException("Unsupported Term type " + term.getClass().getName());
+        }
+    }
+
+    private String toLiteralTermExpression(Field field, TypeReference resultType, Literal literal, Function<VariableLiteral, String> variableExpressionGenerator, Tracer tracer) {
+        tracer = tracer.dive("literal term instanceOf");
+        if (literal instanceof NullLiteral) {
+            tracer = tracer.dive("null literal instanceOf");
+            return tracer + "null";
+        } else if (literal instanceof BooleanLiteral) {
+            tracer = tracer.dive("boolean literal instanceOf");
+            return tracer + Boolean.toString(((BooleanLiteral) literal).getValue());
+        } else if (literal instanceof NumericLiteral) {
+            tracer = tracer.dive("numeric literal instanceOf");
+            final String numberString = ((NumericLiteral) literal).getNumber().toString();
+            if (resultType.isIntegerTypeReference()) {
+                final IntegerTypeReference integerTypeReference = resultType.asIntegerTypeReference().orElseThrow(RuntimeException::new);
+                if (integerTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.UINT && integerTypeReference.getSizeInBits() >= 32) {
+                    tracer = tracer.dive("uint >= 32bit");
+                    return tracer + numberString + "L";
+                } else if (integerTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.INT && integerTypeReference.getSizeInBits() > 32) {
+                    tracer = tracer.dive("int > 32bit");
+                    return tracer + numberString + "L";
+                }
+            } else if (resultType.isFloatTypeReference()) {
+                final FloatTypeReference floatTypeReference = resultType.asFloatTypeReference().orElseThrow(RuntimeException::new);
+                if (floatTypeReference.getSizeInBits() <= 32) {
+                    tracer = tracer.dive("float < 32bit");
+                    return tracer + numberString + "F";
+                }
+            }
+            return tracer + numberString;
+        } else if (literal instanceof HexadecimalLiteral) {
+            tracer = tracer.dive("hexadecimal literal instanceOf");
+            final String hexString = ((HexadecimalLiteral) literal).getHexString();
+            if (resultType.isIntegerTypeReference()) {
+                final IntegerTypeReference integerTypeReference = resultType.asIntegerTypeReference().orElseThrow(RuntimeException::new);
+                if (integerTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.UINT && integerTypeReference.getSizeInBits() >= 32) {
+                    tracer = tracer.dive("uint >= 32bit");
+                    return tracer + hexString + "L";
+                } else if (integerTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.INT && integerTypeReference.getSizeInBits() > 32) {
+                    tracer = tracer.dive("int > 32bit");
+                    return tracer + hexString + "L";
+                }
+            }
+            return tracer + hexString;
+        } else if (literal instanceof StringLiteral) {
+            tracer = tracer.dive("string literal instanceOf");
+            return tracer + "\"" + ((StringLiteral) literal).getValue() + "\"";
+        } else if (literal instanceof VariableLiteral) {
+            tracer = tracer.dive("variable literal instanceOf");
+            VariableLiteral variableLiteral = (VariableLiteral) literal;
+            if ("curPos".equals(((VariableLiteral) literal).getName())) {
+                return "(readBuffer.getPos() - startPos)";
+            }
+            // If this literal references an Enum type, then we have to output it differently.
+            if (getTypeDefinitions().get(variableLiteral.getName()) instanceof EnumTypeDefinition) {
+                tracer = tracer.dive("enum definition instanceOf");
+                VariableLiteral enumDefinitionChild = variableLiteral.getChild()
+                    .orElseThrow(() -> new RuntimeException("enum definitions should have childs"));
+                return tracer + variableLiteral.getName() + "." + enumDefinitionChild.getName() +
+                    enumDefinitionChild.getChild().map(child -> "." + toVariableExpressionRest(field, resultType, child)).orElse("");
+            } else {
+                return tracer + variableExpressionGenerator.apply(variableLiteral);
+            }
+        } else {
+            throw new RuntimeException("Unsupported Literal type " + literal.getClass().getName());
+        }
+    }
+
+    private String toUnaryTermExpression(Field field, TypeReference resultType, UnaryTerm unaryTerm, Function<VariableLiteral, String> variableExpressionGenerator, Tracer tracer) {
+        tracer = tracer.dive("unary term instanceOf");
+        Term a = unaryTerm.getA();
+        switch (unaryTerm.getOperation()) {
+            case "!":
+                tracer = tracer.dive("case !");
+                if ((resultType != getAnyTypeReference()) && !resultType.isBooleanTypeReference()) {
+                    throw new IllegalArgumentException("'!(...)' expression requires boolean type");
+                }
+                return tracer + "!(" + toExpression(field, resultType, a, variableExpressionGenerator) + ")";
+            case "-":
+                tracer = tracer.dive("case -");
+                if ((resultType != getAnyTypeReference()) && !resultType.isIntegerTypeReference() && !resultType.isFloatTypeReference()) {
+                    throw new IllegalArgumentException("'-(...)' expression requires integer or floating-point type");
+                }
+                return tracer + "-(" + toExpression(field, resultType, a, variableExpressionGenerator) + ")";
+            case "()":
+                tracer = tracer.dive("case ()");
+                return tracer + "(" + toExpression(field, resultType, a, variableExpressionGenerator) + ")";
+            default:
+                throw new RuntimeException("Unsupported unary operation type " + unaryTerm.getOperation());
+        }
+    }
+
+    private String toBinaryTermExpression(Field field, TypeReference resultType, BinaryTerm binaryTerm, Function<VariableLiteral, String> variableExpressionGenerator, Tracer tracer) {
+        tracer = tracer.dive("binary term instanceOf");
+        Term a = binaryTerm.getA();
+        Term b = binaryTerm.getB();
+        String operation = binaryTerm.getOperation();
+        switch (operation) {
+            case "^": {
+                tracer = tracer.dive(operation);
+                if ((resultType != getAnyTypeReference()) && !resultType.isIntegerTypeReference() && !resultType.isFloatTypeReference()) {
+                    throw new IllegalArgumentException("'A^B' expression requires numeric result type");
+                }
+                return tracer + "Math.pow((" + toExpression(field, resultType, a, variableExpressionGenerator) + "), (" + toExpression(field, resultType, b, variableExpressionGenerator) + "))";
+            }
+            case "*":
+            case "/":
+            case "%":
+            case "+":
+            case "-": {
+                tracer = tracer.dive(operation);
+                if ((resultType != getAnyTypeReference()) && !resultType.isIntegerTypeReference() && !resultType.isFloatTypeReference()) {
+                    throw new IllegalArgumentException("'A" + operation + "B' expression requires numeric result type");
+                }
+                return tracer + "(" + toExpression(field, resultType, a, variableExpressionGenerator) + ") " + operation + " (" + toExpression(field, resultType, b, variableExpressionGenerator) + ")";
+            }
+            case ">>":
+            case "<<": {
+                tracer = tracer.dive(operation);
+                return tracer + "(" + toExpression(field, resultType, a, variableExpressionGenerator) + ") " + operation + " (" + toExpression(field, INT_TYPE_REFERENCE, b, variableExpressionGenerator) + ")";
+            }
+            case ">=":
+            case "<=":
+            case ">":
+            case "<":
+            case "==":
+            case "!=": {
+                if ((resultType != getAnyTypeReference()) && !resultType.isBooleanTypeReference()) {
+                    throw new IllegalArgumentException("'A" + operation + "B' expression requires boolean result type");
+                }
+                // TODO: Try to infer the types of the arguments in this case
+                return tracer + "(" + toExpression(field, ANY_TYPE_REFERENCE, a, variableExpressionGenerator) + ") " + operation + " (" + toExpression(field, ANY_TYPE_REFERENCE, b, variableExpressionGenerator) + ")";
+            }
+            case "&&":
+            case "||": {
+                if ((resultType != getAnyTypeReference()) && !resultType.isBooleanTypeReference()) {
+                    throw new IllegalArgumentException("'A" + operation + "B' expression requires boolean result type");
+                }
+                return tracer + "(" + toExpression(field, resultType, a, variableExpressionGenerator) + ") " + operation + " (" + toExpression(field, resultType, b, variableExpressionGenerator) + ")";
+            }
+            case "&":
+            case "|": {
+                throw new IllegalArgumentException("Implement this some day ...");
+            }
+            default: {
+                throw new IllegalArgumentException("Unsupported ternary operation type " + operation);
+            }
+        }
+    }
+
+    private String toTernaryTermExpression(Field field, TypeReference resultType, TernaryTerm ternaryTerm, Function<VariableLiteral, String> variableExpressionGenerator, Tracer tracer) {
+        tracer = tracer.dive("ternary term instanceOf");
+        if ("if".equals(ternaryTerm.getOperation())) {
+            Term a = ternaryTerm.getA();
+            Term b = ternaryTerm.getB();
+            Term c = ternaryTerm.getC();
+            return tracer +
+                "(" +
+                "(" + toExpression(field, BOOL_TYPE_REFERENCE, a, variableExpressionGenerator) + ") ? " +
+                toExpression(field, resultType, b, variableExpressionGenerator) + " : " +
+                toExpression(field, resultType, c, variableExpressionGenerator) + "" +
+                ")";
+        } else {
+            throw new IllegalArgumentException("Unsupported ternary operation type " + ternaryTerm.getOperation());
+        }
+    }
+
+    public String toVariableEnumAccessExpression(VariableLiteral variableLiteral) {
+        return variableLiteral.getName();
+    }
+
+    private String toVariableParseExpression(Field field, TypeReference resultType, VariableLiteral variableLiteral, List<Argument> parserArguments) {
+        Tracer tracer = Tracer.start("toVariableParseExpression");
+        // CAST expressions are special as we need to add a ".class" to the second parameter in Java.
+        if ("CAST".equals(variableLiteral.getName())) {
+            return toCastVariableParseExpression(field, resultType, variableLiteral, parserArguments, tracer);
+        }
+        // Special handling for ByteOrder enums (Built in enums)
+        else if ("BIG_ENDIAN".equals(variableLiteral.getName())) {
+            return "ByteOrder.BIG_ENDIAN";
+        } else if ("LITTLE_ENDIAN".equals(variableLiteral.getName())) {
+            return "ByteOrder.LITTLE_ENDIAN";
+        }
+        // If we're referencing an implicit field, we need to handle that differently.
+        else if (isVariableLiteralImplicitField(variableLiteral)) { // If we are accessing implicit fields, we need to rely on a local variable instead.
+            return toImplicitVariableParseExpression(field, resultType, variableLiteral, tracer);
+        }
+        // Call a static function in the drivers StaticHelper
+        else if ("STATIC_CALL".equals(variableLiteral.getName())) {
+            return toStaticCallParseExpression(field, resultType, variableLiteral, parserArguments, tracer);
+        }
+        // Call a built-in global static function
+        else if (variableLiteral.getName().equals(variableLiteral.getName().toUpperCase())) { // All uppercase names are not fields, but utility methods.
+            return toFunctionCallParseExpression(field, resultType, variableLiteral, parserArguments, tracer);
+        }
+        // The synthetic checksumRawData is a local field and should not be accessed as bean property.
+        boolean isParserArg = "readBuffer".equals(variableLiteral.getName());
+        boolean isTypeArg = "_type".equals(variableLiteral.getName());
+        if (!isParserArg && !isTypeArg && parserArguments != null) {
+            for (Argument serializerArgument : parserArguments) {
+                if (serializerArgument.getName().equals(variableLiteral.getName())) {
+                    isParserArg = true;
+                    break;
+                }
+            }
+        }
+        if (isParserArg) {
+            tracer = tracer.dive("parser arg");
+            return tracer + variableLiteral.getName() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(field, resultType, child)).orElse("");
+        } else if (isTypeArg) {
+            tracer = tracer.dive("type arg");
+            String part = variableLiteral.getChild().map(VariableLiteral::getName).orElse("");
+            switch (part) {
+                case "name":
+                    return tracer + "\"" + field.getTypeName() + "\"";
+                case "length":
+                    return tracer + "\"" + ((SimpleTypeReference) field).getSizeInBits() + "\"";
+                case "encoding":
+                    String encoding = ((StringLiteral) field.getEncoding().orElse(new DefaultStringLiteral("UTF-8"))).getValue();
+                    return tracer + "\"" + encoding + "\"";
+                default:
+                    return tracer + "";
+            }
+        } else {
+            return tracer + variableLiteral.getName() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(field, resultType, child)).orElse("");
+        }
+    }
+
+    private String toCastVariableParseExpression(Field field, TypeReference resultType, VariableLiteral variableLiteral, List<Argument> parserArguments, Tracer tracer) {
+        tracer = tracer.dive("CAST");
+        List<Term> arguments = variableLiteral.getArgs().orElseThrow(() -> new RuntimeException("A Cast expression needs arguments"));
+        if (arguments.size() != 2) {
+            throw new RuntimeException("A CAST expression expects exactly two arguments.");
+        }
+        VariableLiteral firstArgument = arguments.get(0).asLiteral()
+            .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
+            .asVariableLiteral()
+            .orElseThrow(() -> new RuntimeException("First argument should be a Variable literal"));
+        StringLiteral typeArgument = arguments.get(1).asLiteral().orElseThrow(() -> new RuntimeException("Second argument should be a String literal"))
+            .asStringLiteral()
+            .orElseThrow(() -> new RuntimeException("Second argument should be a String literal"));
+        String sb = "CAST" + "(" +
+            toVariableParseExpression(field, ANY_TYPE_REFERENCE, firstArgument, parserArguments) +
+            ", " +
+            typeArgument.getValue() + ".class)";
+        return tracer + sb + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(field, resultType, child)).orElse("");
+    }
+
+    private String toImplicitVariableParseExpression(Field field, TypeReference resultType, VariableLiteral variableLiteral, Tracer tracer) {
+        tracer = tracer.dive("implicit");
+        return tracer + variableLiteral.getName();
+    }
+
+    private String toStaticCallParseExpression(Field field, TypeReference resultType, VariableLiteral variableLiteral, List<Argument> parserArguments, Tracer tracer) {
+        tracer = tracer.dive("STATIC_CALL");
+        List<Term> arguments = variableLiteral.getArgs().orElseThrow(() -> new RuntimeException("A STATIC_CALL expression needs arguments"));
+        if (arguments.size() < 1) {
+            throw new RuntimeException("A STATIC_CALL expression expects at least one argument.");
+        }
+        // TODO: make it as static import with a emitImport so if a static call is present a "utils" package must be present in the import
+        StringBuilder sb = new StringBuilder();
+        sb.append(packageName()).append(".utils.StaticHelper.");
+        // Get the class and method name
+        String methodName = arguments.get(0).asLiteral()
+            .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
+            .asStringLiteral()
+            .orElseThrow(() -> new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral")).
+            getValue();
+        sb.append(methodName).append("(");
+        for (int i = 1; i < arguments.size(); i++) {
+            Term arg = arguments.get(i);
+            if (i > 1) {
+                sb.append(", ");
+            }
+            sb.append(toParseExpression(field, ANY_TYPE_REFERENCE, arg, parserArguments));
+           /*if (arg instanceof VariableLiteral) {
+                VariableLiteral variableLiteralArg = (VariableLiteral) arg;
+                // "readBuffer" is the default name of the reader argument which is always available.
+                boolean isParserArg = "readBuffer".equals(variableLiteralArg.getName());
+                boolean isTypeArg = "_type".equals(variableLiteralArg.getName());
+                if (!isParserArg && !isTypeArg && parserArguments != null) {
+                    for (Argument parserArgument : parserArguments) {
+                        if (parserArgument.getName().equals(variableLiteralArg.getName())) {
+                            isParserArg = true;
+                            break;
+                        }
+                    }
+                }
+                if (isParserArg) {
+                    sb.append(variableLiteralArg.getName()).append(variableLiteralArg.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
+                } else if (isTypeArg) {// We have to manually evaluate the type information at code-generation time.
+                    String part = variableLiteralArg.getChild().map(VariableLiteral::getName).orElse("");
+                    switch (part) {
+                        case "name":
+                            sb.append("\"").append(field.getTypeName()).append("\"");
+                            break;
+                        case "length":
+                            sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
+                            break;
+                        case "encoding":
+                            String encoding = ((StringLiteral) field.getEncoding().orElse(new DefaultStringLiteral("UTF-8"))).getValue();
+                            sb.append("\"").append(encoding).append("\"");
+                            break;
+                    }
+                } else {
+                    sb.append(toVariableParseExpression(field, variableLiteralArg, null));
+                }
+            } else if (arg instanceof StringLiteral) {
+                sb.append(((StringLiteral) arg).getValue());
+            }*/
+        }
+        sb.append(")");
+        if (variableLiteral.getIndex() != VariableLiteral.NO_INDEX) {
+            // TODO: If this is a byte typed field, this needs to be an array accessor instead.
+            sb.append(".get(").append(variableLiteral.getIndex()).append(")");
+        }
+        return tracer + sb.toString();
+    }
+
+    private String toFunctionCallParseExpression(Field field, TypeReference resultType, VariableLiteral variableLiteral, List<Argument> parserArguments, Tracer tracer) {
+        tracer = tracer.dive("FunctionCall");
+        StringBuilder sb = new StringBuilder(variableLiteral.getName());
+        if (variableLiteral.getArgs().isPresent()) {
+            sb.append("(");
+            boolean firstArg = true;
+            for (Term arg : variableLiteral.getArgs().get()) {
+                if (!firstArg) {
+                    sb.append(", ");
+                }
+                // TODO: Try to infer the type of the argument ...
+                sb.append(toParseExpression(field, ANY_TYPE_REFERENCE, arg, parserArguments));
+                firstArg = false;
+            }
+            sb.append(")");
+        }
+        if (variableLiteral.getIndex() != VariableLiteral.NO_INDEX) {
+            // TODO: If this is a byte typed field, this needs to be an array accessor instead.
+            sb.append(".get(").append(variableLiteral.getIndex()).append(")");
+        }
+        return tracer + sb.toString() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(field, resultType, child)).orElse("");
+    }
+
+    private String toVariableSerializationExpression(Field field, TypeReference resultType, VariableLiteral variableLiteral, List<Argument> serialzerArguments) {
+        Tracer tracer = Tracer.start("variable serialization expression");
+        if ("STATIC_CALL".equals(variableLiteral.getName())) {
+            return toStaticCallSerializationExpression(field, resultType, variableLiteral, serialzerArguments, tracer);
+        }
+        // All uppercase names are not fields, but utility methods.
+        else if (variableLiteral.getName().equals(variableLiteral.getName().toUpperCase())) {
+            return toGlobalFunctionCallSerializationExpression(field, resultType, variableLiteral, serialzerArguments, tracer);
+        } else if (isVariableLiteralImplicitField(variableLiteral)) { // If we are accessing implicit fields, we need to rely on a local variable instead.
+            tracer = tracer.dive("implicit field");
+            final ImplicitField referencedImplicitField = getReferencedImplicitField(variableLiteral);
+            return tracer + toSerializationExpression(referencedImplicitField, referencedImplicitField.getType(), getReferencedImplicitField(variableLiteral).getSerializeExpression(), serialzerArguments);
+        } else if (isVariableLiteralVirtualField(variableLiteral)) {
+            tracer = tracer.dive("virtual field");
+            return tracer + toVariableExpressionRest(field, resultType, variableLiteral);
+        }
+        // The synthetic checksumRawData is a local field and should not be accessed as bean property.
+        boolean isSerializerArg = "writeBuffer".equals(variableLiteral.getName()) || "checksumRawData".equals(variableLiteral.getName()) || "_value".equals(variableLiteral.getName()) || "element".equals(variableLiteral.getName()) || "size".equals(variableLiteral.getName());
+        boolean isTypeArg = "_type".equals(variableLiteral.getName());
+        if (!isSerializerArg && !isTypeArg && serialzerArguments != null) {
+            for (Argument serializerArgument : serialzerArguments) {
+                if (serializerArgument.getName().equals(variableLiteral.getName())) {
+                    isSerializerArg = true;
+                    break;
+                }
+            }
+        }
+        if (isSerializerArg) {
+            tracer = tracer.dive("serializer arg");
+            return tracer + variableLiteral.getName() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(field, resultType, child)).orElse("");
+        } else if (isTypeArg) {
+            tracer = tracer.dive("type arg");
+            String part = variableLiteral.getChild().map(VariableLiteral::getName).orElse("");
+            switch (part) {
+                case "name":
+                    return tracer + "\"" + field.getTypeName() + "\"";
+                case "length":
+                    return tracer + "\"" + ((SimpleTypeReference) field).getSizeInBits() + "\"";
+                case "encoding":
+                    String encoding = ((StringLiteral) field.getEncoding().orElse(new DefaultStringLiteral("UTF-8"))).getValue();
+                    return tracer + "\"" + encoding + "\"";
+                default:
+                    return tracer + "";
+            }
+        } else {
+            return tracer + toVariableExpressionRest(field, resultType, variableLiteral);
+        }
+    }
+
+    private String toGlobalFunctionCallSerializationExpression(Field field, TypeReference resultType, VariableLiteral variableLiteral, List<Argument> serialzerArguments, Tracer tracer) {
+        tracer = tracer.dive("GLOBAL_FUNCTION_CALL");
+        StringBuilder sb = new StringBuilder(variableLiteral.getName());
+        if (variableLiteral.getArgs().isPresent()) {
+            sb.append("(");
+            boolean firstArg = true;
+            for (Term arg : variableLiteral.getArgs().get()) {
+                if (!firstArg) {
+                    sb.append(", ");
+                }
+                sb.append(toSerializationExpression(field, ANY_TYPE_REFERENCE, arg, serialzerArguments));
+                firstArg = false;
+                /*if (arg instanceof VariableLiteral) {
+                    VariableLiteral va = (VariableLiteral) arg;
+                    boolean isSerializerArg = "readBuffer".equals(va.getName()) || "writeBuffer".equals(va.getName());
+                    boolean isTypeArg = "_type".equals(va.getName());
+                    if (!isSerializerArg && !isTypeArg && serialzerArguments != null) {
+                        for (Argument serializerArgument : serialzerArguments) {
+                            if (serializerArgument.getName().equals(va.getName())) {
+                                isSerializerArg = true;
+                                break;
+                            }
+                        }
+                    }
+                    if (isSerializerArg) {
+                        sb.append(va.getName()).append(va.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
+                    } else if (isTypeArg) {
+                        String part = va.getChild().map(VariableLiteral::getName).orElse("");
+                        switch (part) {
+                            case "name":
+                                sb.append("\"").append(field.getTypeName()).append("\"");
+                                break;
+                            case "length":
+                                sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
+                                break;
+                            case "encoding":
+                                String encoding = ((StringLiteral) field.getEncoding().orElse(new DefaultStringLiteral("UTF-8"))).getValue();
+                                sb.append("\"").append(encoding).append("\"");
+                                break;
+                        }
+                    } else {
+                        sb.append(toVariableSerializationExpression(field, va, serialzerArguments));
+                    }
+                } else if (arg instanceof StringLiteral) {
+                    sb.append(((StringLiteral) arg).getValue());
+                }*/
+            }
+            sb.append(")");
+        }
+        return tracer + sb.toString();
+    }
+
+    private String toStaticCallSerializationExpression(Field field, TypeReference resultType, VariableLiteral variableLiteral, List<Argument> serialzerArguments, Tracer tracer) {
+        tracer = tracer.dive("STATIC_CALL");
+        StringBuilder sb = new StringBuilder();
+        List<Term> arguments = variableLiteral.getArgs().orElseThrow(() -> new RuntimeException("A STATIC_CALL expression needs arguments"));
+        if (arguments.size() < 1) {
+            throw new RuntimeException("A STATIC_CALL expression expects at least one argument.");
+        }
+        // TODO: make it as static import with a emitImport so if a static call is present a "utils" package must be present in the import
+        sb.append(packageName()).append(".utils.StaticHelper.");
+        // Get the class and method name
+        String methodName = arguments.get(0).asLiteral()
+            .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
+            .asStringLiteral()
+            .orElseThrow(() -> new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral")).
+            getValue();
+        //methodName = methodName.substring(1, methodName.length() - 1);
+        sb.append(methodName).append("(");
+        for (int i = 1; i < arguments.size(); i++) {
+            Term arg = arguments.get(i);
+            if (i > 1) {
+                sb.append(", ");
+            }
+            sb.append(toSerializationExpression(field, ANY_TYPE_REFERENCE, arg, serialzerArguments));
+            /*if (arg instanceof VariableLiteral) {
+                VariableLiteral va = (VariableLiteral) arg;
+                // "readBuffer" and "_value" are always available in every parser.
+                boolean isSerializerArg = "readBuffer".equals(va.getName()) || "writeBuffer".equals(va.getName()) || "_value".equals(va.getName()) || "element".equals(va.getName());
+                boolean isTypeArg = "_type".equals(va.getName());
+                if (!isSerializerArg && !isTypeArg && serialzerArguments != null) {
+                    for (Argument serializerArgument : serialzerArguments) {
+                        if (serializerArgument.getName().equals(va.getName())) {
+                            isSerializerArg = true;
+                            break;
+                        }
+                    }
+                }
+                if (isSerializerArg) {
+                    sb.append(va.getName()).append(va.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
+                } else if (isTypeArg) {
+                    String part = va.getChild().map(VariableLiteral::getName).orElse("");
+                    switch (part) {
+                        case "name":
+                            sb.append("\"").append(field.getTypeName()).append("\"");
+                            break;
+                        case "length":
+                            sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
+                            break;
+                        case "encoding":
+                            String encoding = ((StringLiteral) field.getEncoding().orElse(new DefaultStringLiteral("UTF-8"))).getValue();
+                            sb.append("\"").append(encoding).append("\"");
+                            break;
+                    }
+                } else {
+                    sb.append(toVariableSerializationExpression(field, va, serialzerArguments));
+                }
+            } else if (arg instanceof StringLiteral) {
+                sb.append(((StringLiteral) arg).getValue());
+            }*/
+        }
+        sb.append(")");
+        return tracer + sb.toString();
+    }
+
+    private String toVariableExpressionRest(Field field, TypeReference resultType, VariableLiteral variableLiteral) {
+        Tracer tracer = Tracer.start("variable expression rest");
+        // length is kind of a keyword in mspec, so we shouldn't be naming variables length. if we ask for the length of a object we can just return length().
+        // This way we can get the length of a string when serializing
+        String variableLiteralName = variableLiteral.getName();
+        if (variableLiteralName.equals("length")) {
+            tracer = tracer.dive("length");
+            return tracer + variableLiteralName + "()" + ((variableLiteral.isIndexed() ? ".get(" + variableLiteral.getIndex() + ")" : "") +
+                variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(field, resultType, child)).orElse(""));
+        }
+        return tracer + "get" + WordUtils.capitalize(variableLiteralName) + "()" + ((variableLiteral.isIndexed() ? ".get(" + variableLiteral.getIndex() + ")" : "") +
+            variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(field, resultType, child)).orElse(""));
+    }
+
+    public String getSizeInBits(ComplexTypeDefinition complexTypeDefinition, List<Argument> parserArguments) {
+        int sizeInBits = 0;
+        StringBuilder sb = new StringBuilder();
+        for (Field field : complexTypeDefinition.getFields()) {
+            if (field instanceof ArrayField) {
+                ArrayField arrayField = (ArrayField) field;
+                final SimpleTypeReference type = (SimpleTypeReference) arrayField.getType();
+                switch (arrayField.getLoopType()) {
+                    case COUNT:
+                        sb.append("(").append(toSerializationExpression(null, INT_TYPE_REFERENCE, arrayField.getLoopExpression(), parserArguments)).append(" * ").append(type.getSizeInBits()).append(") + ");
+                        break;
+                    case LENGTH:
+                        sb.append("(").append(toSerializationExpression(null, INT_TYPE_REFERENCE, arrayField.getLoopExpression(), parserArguments)).append(" * 8) + ");
+                        break;
+                    case TERMINATED:
+                        // No terminated.
+                        break;
+                }
+            } else if (field instanceof TypedField) {
+                TypedField typedField = (TypedField) field;
+                final TypeReference type = typedField.getType();
+                if (field instanceof ManualField) {
+                    ManualField manualField = (ManualField) field;
+                    sb.append("(").append(toSerializationExpression(null, INT_TYPE_REFERENCE, manualField.getLengthExpression(), parserArguments)).append(") + ");
+                } else if (type instanceof SimpleTypeReference) {
+                    SimpleTypeReference simpleTypeReference = (SimpleTypeReference) type;
+                    if (simpleTypeReference instanceof VstringTypeReference) {
+                        sb.append(toSerializationExpression(null, INT_TYPE_REFERENCE, ((VstringTypeReference) simpleTypeReference).getLengthExpression(), parserArguments)).append(" + ");
+                    } else {
+                        sizeInBits += simpleTypeReference.getSizeInBits();
+                    }
+                }
+            }
+        }
+        return sb.toString() + sizeInBits;
+    }
+
+    public String escapeValue(TypeReference typeReference, String valueString) {
+        if (valueString == null) {
+            return null;
+        }
+        if (typeReference instanceof SimpleTypeReference) {
+            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
+            switch (simpleTypeReference.getBaseType()) {
+                case UINT:
+                case INT:
+                    // If it's a one character string and is numeric, output it as char.
+                    if (!NumberUtils.isParsable(valueString) && (valueString.length() == 1)) {
+                        return "'" + valueString + "'";
+                    }
+                    break;
+                case STRING:
+                case VSTRING:
+                    return "\"" + valueString + "\"";
+            }
+        } else if (isEnumTypeReference(typeReference)) {
+            return "model." + typeReference.asComplexTypeReference().orElseThrow().getName() + "." + valueString;
+        }
+        return valueString;
+    }
+
+    public String getFieldOptions(TypedField field, List<Argument> parserArguments) {
+        StringBuilder sb = new StringBuilder();
+        final Optional<Term> encodingOptional = field.getEncoding();
+        if (encodingOptional.isPresent()) {
+            final String encoding = toParseExpression(field, field.getType(), encodingOptional.get(), parserArguments);
+            sb.append(", WithOption.WithEncoding(").append(encoding).append(")");
+        }
+        final Optional<Term> byteOrderOptional = field.getByteOrder();
+        if (byteOrderOptional.isPresent()) {
+            final String byteOrder = toParseExpression(field, field.getType(), byteOrderOptional.get(), parserArguments);
+            sb.append(", WithOption.WithByteOrder(").append(byteOrder).append(")");
+        }
+        return sb.toString();
+    }
+
+}
diff --git a/build-utils/language-cs/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput b/code-generation/language-cs/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput
similarity index 100%
rename from build-utils/language-cs/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput
rename to code-generation/language-cs/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput
diff --git a/code-generation/language-cs/src/main/resources/templates/cs/data-io-template.cs.ftlh b/code-generation/language-cs/src/main/resources/templates/cs/data-io-template.cs.ftlh
new file mode 100644
index 0000000..38572af
--- /dev/null
+++ b/code-generation/language-cs/src/main/resources/templates/cs/data-io-template.cs.ftlh
@@ -0,0 +1,437 @@
+<#--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<#-- Prevent freemarker from escaping stuff -->
+<#outputformat "undefined">
+<#-- Declare the name and type of variables passed in to the template -->
+<#-- @ftlvariable name="languageName" type="java.lang.String" -->
+<#-- @ftlvariable name="protocolName" type="java.lang.String" -->
+<#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
+<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.cs.CsLanguageTemplateHelper" -->
+<#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
+<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/model/${type.name}.cs
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Code generated by code-generation. DO NOT EDIT.
+
+using System;
+using System.Collections.Generic;
+using NLog;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+<#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
+<#if type.parserArguments.isPresent()><#assign parserArguments=type.parserArguments.orElseThrow()></#if>
+namespace org.apache.plc4net.drivers.${protocolName?replace("-", "")}.${outputFlavor?replace("-", "")}.model
+{
+
+    public class ${type.name}
+    {
+
+        private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();
+
+        public static IPlcValue StaticParse(ReadBuffer readBuffer<#if type.parserArguments.isPresent()>, <#list type.parserArguments.orElseThrow() as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>)
+        {
+        <#assign defaultCaseOutput=false>
+        <#assign dataIoTypeDefinition=type.asDataIoTypeDefinition().orElseThrow()>
+        <#list dataIoTypeDefinition.switchField.cases as case>
+            <@compress single_line=true>
+                <#if case.discriminatorValueTerms?has_content>
+                    if(
+                    <#list case.discriminatorValueTerms as discriminatorValueTerm>
+                        <#assign discriminatorExpression=dataIoTypeDefinition.switchField.discriminatorExpressions[discriminatorValueTerm?index].asLiteral().orElseThrow().asVariableLiteral().orElseThrow()>
+                        <#assign discriminatorType=helper.getDiscriminatorTypes()[discriminatorExpression.name]>
+                        ${helper.toParseExpression(dataIoTypeDefinition.switchField, discriminatorType, discriminatorExpression, parserArguments)} ==
+                        <#if helper.isEnumTypeReference(discriminatorType)>
+                        ${helper.getLanguageTypeNameForTypeReference(discriminatorType)}.${helper.toParseExpression(dataIoTypeDefinition.switchField, discriminatorType, discriminatorValueTerm, parserArguments)}
+                        <#else>
+                        ${helper.toParseExpression(dataIoTypeDefinition.switchField, discriminatorType, discriminatorValueTerm, parserArguments)}
+                        </#if>
+                        <#sep> && </#sep>
+                    </#list>
+                    )
+                <#else>
+                    <#assign defaultCaseOutput=true>
+                </#if>
+            </...@compress> { // ${case.name}
+            <#assign valueDefined=false>
+            <#list case.fields as field>
+                <#switch field.typeName>
+                    <#case "array">
+                        <#assign arrayField = field.asArrayField().orElseThrow()>
+                // Array field (${arrayField.name})
+                <#-- Only update curPos if the length expression uses it -->
+                        <#if arrayField.loopExpression.contains("curPos")>
+                curPos = readBuffer.getPos() - startPos;
+                        </#if>
+                <#-- If this is a count array, we can directly initialize an array with the given size -->
+                        <#if field.isCountArrayField()>
+                // Count array
+                List<IPlcValue> ${arrayField.name};
+                {
+                    var itemCount = ${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression,parserArguments)};
+                    ${arrayField.name} = new List<IPlcValue>();
+                    for (var curItem = 0; curItem < itemCount; curItem++) {
+                        ${arrayField.name}.Add(new ${helper.getPlcValueTypeForTypeReference(arrayField.type)}(<#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)})<#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.StaticParse(readBuffer<#if arrayField.params.isPresent()>, <#list arrayField.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNameForTy [...]
+                    }
+                }
+                <#-- In all other cases do we have to work with a list, that is later converted to an array -->
+                        <#else>
+                <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
+                            <#if arrayField.isLengthArrayField()>
+                // Length array
+                var _${arrayField.name}Length = ${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression,parserArguments)};
+                var ${arrayField.name}EndPos = readBuffer.getPos() + _${arrayField.name}Length;
+                var value = new List<IPlcValue>();
+                while(readBuffer.getPos() < ${arrayField.name}EndPos) {
+                    value.Add(
+                <#if helper.isSimpleTypeReference(arrayField.type)>
+                        new ${helper.getPlcValueTypeForTypeReference(arrayField.type)}(${helper.getReadBufferReadMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)})
+                <#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.StaticParse(readBuffer
+                    <#if arrayField.params.isPresent()>,
+                        <#list arrayField.params.orElseThrow() as parserArgument>
+                                (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index))}) (${helper.toParseExpression(arrayField,arrayField.type, parserArgument,parserArguments)})
+                            <#sep>, </#sep>
+                        </#list>
+                    </#if>
+                        )
+                </#if>
+                    );
+                }
+                <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
+                            <#elseif arrayField.isTerminatedArrayField()>
+                // Terminated array
+                var ${arrayField.name} = new List<${helper.getLanguageTypeNameForField(arrayField)}>();
+                while(!((boolean) (${helper.toParseExpression(arrayField, helper.boolTypeReference, arrayField.loopExpression,parserArguments)}))) {
+                    ${arrayField.name}.Add(<#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}<#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.StaticParse(readBuffer<#if arrayField.params.isPresent()>, <#list arrayField.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?i [...]
+
+                <#-- After parsing, update the current position, but only if it's needed -->
+                                <#if arrayField.loopExpression.contains("curPos")>
+                    curPos = readBuffer.getPos() - startPos;
+                                </#if>
+                }
+                            </#if>
+                        </#if>
+                        <#if arrayField.name == "value">
+                            <#assign valueDefined=true>
+                        </#if>
+                    <#break>
+                    <#case "const">
+                        <#assign constField=field.asConstField().orElseThrow()>
+
+                // Const Field (${constField.name})
+                var ${constField.name} = ${helper.getReadBufferReadMethodCall(constField.type.asSimpleTypeReference().orElseThrow(), "", constField)};
+                if(${constField.name} != ${dataIoTypeDefinition.name}.${constField.name?upper_case}) {
+                    throw new ParseException("Expected constant value " + ${dataIoTypeDefinition.name}.${constField.name?upper_case} + " but got " + ${constField.name});
+                }
+                        <#if constField.name == "value">
+                            <#assign valueDefined=true>
+                        </#if>
+                    <#break>
+                    <#case "enum">
+                        <#assign enumField=field.asEnumField().orElseThrow()>
+
+                // Enum field (${enumField.name})
+                var ${enumField.name} = ${helper.getLanguageTypeNameForField(enumField)}.enumForValue(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(enumField.type.asSimpleTypeReference().orElseThrow()), "", enumField)});
+                        <#if enumField.name == "value">
+                            <#assign valueDefined=true>
+                        </#if>
+                    <#break>
+                    <#case "manual">
+                        <#assign manualField=field.asManualField().orElseThrow()>
+
+                // Manual Field (${manualField.name})
+                var ${manualField.name} = (${helper.getLanguageTypeNameForField(manualField)}) (${helper.toParseExpression(manualField, manualField.type, manualField.parseExpression,parserArguments)});
+                        <#if manualField.name == "value">
+                            <#assign valueDefined=true>
+                        </#if>
+                    <#break>
+                    <#case "reserved">
+                        <#assign reservedField=field.asReservedField().orElseThrow()>
+
+                // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
+                {
+                    var reserved = ${helper.getReadBufferReadMethodCall(reservedField.type.asSimpleTypeReference().orElseThrow(), "", reservedField)};
+                    if(reserved != ${helper.getReservedValue(reservedField)}) {
+                        Logger.Info("Expected constant value {expected} but got {got} for reserved field.", ${reservedField.referenceValue}, reserved);
+                    }
+                }
+                    <#break>
+                    <#case "simple">
+                        <#assign simpleField=field.asSimpleField().orElseThrow()>
+
+                        <#if helper.isEnumField(simpleField)>
+                // Enum field (${simpleField.name})
+                var ${simpleField.name} = ${helper.getLanguageTypeNameForField(simpleField)}.enumForValue(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(simpleField.type), "", simpleField)});
+                        <#else>
+                // Simple Field (${simpleField.name})
+                var ${simpleField.name} = <#if helper.isSimpleTypeReference(simpleField.type)>${helper.getReadBufferReadMethodCall(simpleField.type.asSimpleTypeReference().orElseThrow(), "", simpleField)}<#else>${simpleField.type.asComplexTypeReference().orElseThrow().name}IO.StaticParse(readBuffer<#if simpleField.params.isPresent()>, <#list field.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNameForField(helper.getArgumentType(simpleField.type, parserArgument?index), t [...]
+                        </#if>
+                        <#if case.name == "Struct" ||
+                            ((case.name == "DATE_AND_TIME") && ((simpleField.name == "year") || (simpleField.name == "month") || (simpleField.name == "day") || (simpleField.name == "hour") || (simpleField.name == "minutes") || (simpleField.name == "seconds"))) ||
+                            ((case.name == "DATE_AND_TIME") && (simpleField.name == "secondsSinceEpoch")) ||
+                            ((case.name == "DATE") && ((simpleField.name == "year") || (simpleField.name == "month") || (simpleField.name == "day"))) ||
+                            ((case.name == "TIME_OF_DAY") && ((simpleField.name == "hour") || (simpleField.name == "minutes") || (simpleField.name == "seconds"))) ||
+                        simpleField.name == "value">
+                            <#assign valueDefined=true>
+                        </#if>
+                    <#break>
+                </#switch>
+            </#list>
+            <#if case.name == "Struct">
+
+                <#-- In this case we need to wrap each field in a IPlcValue that matches it's natural type -->
+                var _map = new Dictionary<string, IPlcValue>();
+                <#list case.fields as field>
+                    <#if field.isArrayField()>
+                        <#assign field=field.asArrayField().orElseThrow()>
+                _map["${field.name}"] = new PlcList(${field.name});
+                    <#elseif field.isPropertyField()>
+                        <#assign field=field.asPropertyField().orElseThrow()>
+                        <#switch helper.getLanguageTypeNameForTypeReference(field.type)>
+                            <#case "Boolean">
+                _map["${field.name}"] = new PlcBOOL(${field.name});
+                                <#break>
+                            <#case "Byte">
+                _map["${field.name}"] = new PlcSINT(${field.name});
+                                <#break>
+                            <#case "Short">
+                _map["${field.name}"] = new PlcINT(${field.name});
+                                <#break>
+                            <#case "Integer">
+                _map["${field.name}"] = new PlcDINT(${field.name});
+                                <#break>
+                            <#case "Long">
+                _map["${field.name}"] = new PlcLINT(${field.name});
+                                <#break>
+                            <#case "BigInteger">
+                _map["${field.name}"] = new PlcBigInteger(${field.name});
+                                <#break>
+                            <#case "Float">
+                _map["${field.name}"] = new PlcREAL(${field.name});
+                                <#break>
+                            <#case "Double">
+                _map["${field.name}"] = new PlcLREAL(${field.name});
+                                <#break>
+                            <#case "BigDecimal">
+                _map["${field.name}"] = new PlcBigDecimal(${field.name});
+                                <#break>
+                            <#case "String">
+                _map["${field.name}"] = new PlcSTRING(${field.name});
+                                <#break>
+                            <#case "LocalTime">
+                _map["${field.name}"] = new PlcTIME_OF_DAY(${field.name});
+                                <#break>
+                            <#case "LocalDate">
+                _map["${field.name}"] = new PlcDATE(${field.name});
+                                <#break>
+                            <#case "LocalDateTime">
+                _map["${field.name}"] = new PlcDATE_AND_TIME(${field.name});
+                                <#break>
+                        </#switch>
+                    </#if>
+                </#list>
+                <#assign valueDefined=true>
+            </#if>
+
+            <#if valueDefined>
+                <#switch case.name>
+                    <#case "TIME">
+                return new PlcTIME(TimeSpan.FromSeconds(value));
+                    <#break>
+                    <#case "LTIME">
+                return new PlcTIME(TimeSpan.FromMilliseconds(value));
+                    <#break>
+                    <#case "TIME_OF_DAY">
+                return new PlcTIME_OF_DAY(DateTime.Now); <#-- TODO: Convert uint to time-of-day ... -->
+                    <#break>
+                    <#case "DATE">
+                    <#if helper.hasFieldsWithNames(case.fields, "value")>
+                return new PlcDATE(DateTime.Now); <#-- TODO: Convert ushort to date ... -->
+                    <#elseif helper.hasFieldsWithNames(case.fields, "year", "month", "day")>
+                return new PlcDATE(LocalDate.of(year.intValue(), (month == 0) ? 1 : month.intValue(), (day == 0) ? 1 : day.intValue());
+                    </#if>
+                    <#break>
+                    <#case "TIME_OF_DAY">
+                    <#if helper.hasFieldsWithNames(case.fields, "hour", "minutes", "seconds", "nanos")>
+                LocalTime value = LocalTime.of(hour.intValue(), minutes.intValue(), seconds.intValue(), (int) (nanos / 1000000));
+                    <#elseif helper.hasFieldsWithNames(case.fields, "hour", "minutes", "seconds")>
+                LocalTime value = LocalTime.of(hour.intValue(), minutes.intValue(), seconds.intValue());
+                    </#if>
+                return new PlcTIME_OF_DAY(value);
+                    <#break>
+                    <#case "DATE_AND_TIME">
+                    <#if helper.hasFieldsWithNames(case.fields, "year", "month", "day", "hour", "minutes", "seconds", "nanos")>
+                var value = new DateTime(year, (month == 0) ? 1 : month, (day == 0) ? 1 : day, hour, minutes, seconds, (int) (nanos / 1000000));
+                    <#elseif helper.hasFieldsWithNames(case.fields, "year", "month", "day", "hour", "minutes", "seconds")>
+                var value = new DateTime(year, (month == 0) ? 1 : month, (day == 0) ? 1 : day, hour, minutes, seconds, 0);
+                    <#elseif helper.hasFieldsWithNames(case.fields, "secondsSinceEpoch")>
+                var value = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(value);
+                    </#if>
+                return new PlcDATE_AND_TIME(value);
+                    <#break>
+                    <#case "CHAR">
+                return new PlcCHAR(Convert.ToChar(value));
+                    <#break>
+                    <#case "WCHAR">
+                return new PlcWCHAR(Convert.ToChar(value));
+                    <#break>
+                    <#case "Struct">
+                return new PlcStruct(_map);
+                    <#break>
+                    <#case "List">
+                return new PlcList(value);
+                    <#break>
+                    <#default>
+                return new Plc${case.name}(value);
+                </#switch>
+            </#if>
+            }<#sep> else </#sep></#list>
+        <#if !defaultCaseOutput>
+            return null;
+        </#if>
+        }
+
+<#if outputFlavor != "passive">
+            public static WriteBuffer StaticSerialize(IPlcValue _value<#if type.parserArguments.isPresent()>, <#list type.parserArguments.orElseThrow() as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>)
+            {
+                return StaticSerialize(_value<#if type.parserArguments.isPresent()>, <#list type.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>, ByteOrder.BIG_ENDIAN);
+            }
+
+            public static WriteBuffer StaticSerialize(IPlcValue _value<#if type.parserArguments.isPresent()>, <#list type.parserArguments.orElseThrow() as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>, ByteOrder byteOrder)
+            {
+        <#assign defaultCaseOutput=false>
+        <#assign dataIoTypeDefinition=type.asDataIoTypeDefinition().orElseThrow()>
+        <#list dataIoTypeDefinition.switchField.cases as case>
+        <@compress single_line=true>
+            <#if case.discriminatorValueTerms?has_content>
+                    if(
+                <#list case.discriminatorValueTerms as discriminatorValueTerm>
+                    <#assign discriminatorExpression=dataIoTypeDefinition.switchField.discriminatorExpressions[discriminatorValueTerm?index].asLiteral().orElseThrow().asVariableLiteral().orElseThrow()>
+                    <#assign discriminatorType=helper.getDiscriminatorTypes()[discriminatorExpression.name]>
+                            ${helper.toParseExpression(dataIoTypeDefinition.switchField, discriminatorType, discriminatorExpression, parserArguments)} ==
+                    <#if helper.isEnumTypeReference(discriminatorType)>
+                            ${helper.getLanguageTypeNameForTypeReference(discriminatorType)}.${helper.toParseExpression(dataIoTypeDefinition.switchField, discriminatorType, discriminatorValueTerm, parserArguments)}
+                    <#else>
+                            ${helper.toParseExpression(dataIoTypeDefinition.switchField, discriminatorType, discriminatorValueTerm, parserArguments)}
+                    </#if>
+                    <#sep> && </#sep>
+                </#list>
+                )
+            <#else>
+                <#assign defaultCaseOutput=true>
+            </#if>
+        </...@compress> { // ${case.name}
+                var writeBuffer = new WriteBuffer();
+
+            <#list case.fields as field>
+                <#switch field.typeName>
+                    <#case "array">
+                        <#assign arrayField=field.asArrayField().orElseThrow()>
+                PlcList values = (PlcList) _value;
+
+                        <#if case.name == "Struct">
+                foreach (IPlcValue val in values.GetStruct()["${arrayField.name}"].GetList()) {
+                    ${helper.getLanguageTypeNameForField(arrayField)} value = (${helper.getLanguageTypeNameForField(arrayField)}) val.Get${helper.getLanguageTypeNameForField(arrayField)?cap_first}();
+                    ${helper.getWriteBufferWriteMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "value", arrayField)};
+                }
+                        <#else>
+                foreach (IPlcValue val in values.GetList()) {
+                    ${helper.getLanguageTypeNameForField(arrayField)} value = val.Get${helper.getLanguageTypeNameForField(arrayField)?cap_first}();
+                    ${helper.getWriteBufferWriteMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "(" + arrayField.name + ")", arrayField)};
+                }
+                        </#if>
+
+                    <#if case.name == "BOOL">
+                while (writeBuffer.getPos() < writeBuffer.getData().length) {
+                    writeBuffer.writeBit(false);
+                }
+                    </#if>
+                    <#break>
+                    <#case "const">
+                        <#assign constField=field.asConstField().orElseThrow()>
+                // Const Field (${constField.name})
+                ${helper.getWriteBufferWriteMethodCall(constField.type.asSimpleTypeReference().orElseThrow(), constField.referenceValue, constField)};
+                    <#break>
+                    <#case "enum">
+                        <#assign enumField=field.asEnumField().orElseThrow()>
+                // Enum field (${enumField.name})
+                var ${enumField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${enumField.name?cap_first}();
+                ${helper.getWriteBufferWriteMethodCall(helper.getEnumBaseTypeReference(field.asTypedField().orElseThrow().type), "(" + enumField.name + ".getValue())", enumField)};
+                    <#break>
+                    <#case "manual">
+                        <#assign manualField=field.asManualField().orElseThrow()>
+                // Manual Field (${manualField.name})
+                ${helper.toSerializationExpression(manualField, manualField.type, manualField.serializeExpression, type.parserArguments.orElse(null))};
+                    <#break>
+                    <#case "reserved">
+                        <#assign reservedField=field.asReservedField().orElseThrow()>
+                // Reserved Field
+                ${helper.getWriteBufferWriteMethodCall(reservedField.type.asSimpleTypeReference().orElseThrow(), helper.getReservedValue(reservedField), reservedField)};
+                    <#break>
+                    <#case "simple">
+                        <#assign simpleField=field.asSimpleField().orElseThrow()>
+                // Simple Field (${simpleField.name})
+                        <#if case.name == "Struct">
+                var ${simpleField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.GetStruct()["${simpleField.name}"].Get${helper.getLanguageTypeNameForField(simpleField)?cap_first}();
+                        <#else>
+                            <#if simpleField.name == "value">
+                var ${simpleField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.Get${helper.getLanguageTypeNameForField(simpleField)?cap_first}();
+                            <#else>
+                                <#-- Just for now -->
+                var ${simpleField.name} = ${helper.getNullValueForTypeReference(simpleField.type)};
+                            </#if>
+                        </#if>
+                        <#if helper.isSimpleTypeReference(simpleField.type)>
+                ${helper.getWriteBufferWriteMethodCall(simpleField.type.asSimpleTypeReference().orElseThrow(), "(" + simpleField.name + ")", simpleField)};
+                        <#else>
+                ${simpleField.type.asComplexTypeReference().orElseThrow().name}IO.StaticSerialize(writeBuffer, ${simpleField.name});
+                        </#if>
+                    <#break>
+                </#switch>
+            </#list>
+            return writeBuffer;
+        }<#sep> else </#sep></#list>
+        <#if !defaultCaseOutput>
+        return null;
+        </#if>
+        }
+    }
+</#if>
+
+}
+</#outputformat>
diff --git a/build-utils/language-cs/src/main/resources/templates/cs/enum-template.ftlh b/code-generation/language-cs/src/main/resources/templates/cs/enum-template.cs.ftlh
similarity index 64%
rename from build-utils/language-cs/src/main/resources/templates/cs/enum-template.ftlh
rename to code-generation/language-cs/src/main/resources/templates/cs/enum-template.cs.ftlh
index f65432d..5a5de69 100644
--- a/build-utils/language-cs/src/main/resources/templates/cs/enum-template.ftlh
+++ b/code-generation/language-cs/src/main/resources/templates/cs/enum-template.cs.ftlh
@@ -1,4 +1,5 @@
 <#--
+<#--
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
   distributed with this work for additional information
@@ -23,38 +24,38 @@
 <#-- @ftlvariable name="protocolName" type="java.lang.String" -->
 <#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
 <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.cs.CsLanguageTemplateHelper" -->
+<#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
 <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.EnumTypeDefinition" -->
-<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
 ${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/model/${type.name}.cs
-//
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-//
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Code generated by code-generation. DO NOT EDIT.
 
 namespace org.apache.plc4net.drivers.${protocolName?replace("-", "")}.${outputFlavor?replace("-", "")}.model
 {
 
-    public enum ${type.name}<#if !helper.isStringTypeReference(type.type)> : ${helper.getLanguageTypeNameForTypeReference(type.type)}</#if>
+    public enum ${type.name}
     {
-
     <#list type.enumValues as enumValue>
         ${enumValue.name}<#if !helper.isStringTypeReference(type.type)> = ${enumValue.value}</#if>,
     </#list>
-
     }
 
     <#if type.constantNames?has_content>
@@ -62,13 +63,13 @@ namespace org.apache.plc4net.drivers.${protocolName?replace("-", "")}.${outputFl
     {
         <#list type.constantNames as constantName>
 
-        public static ${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName))} ${constantName?cap_first}(this ${type.name} value)
+        public static ${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName))}<#if helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName)) != 'string'>?</#if> ${constantName?cap_first}(this ${type.name} value)
         {
             switch (value)
             {
             <#list helper.getUniqueEnumValues(type.enumValues) as enumValue>
                 case ${type.name}.${enumValue.name}: { /* '${enumValue.value}' */
-                    return ${helper.escapeEnumValue(type.getConstantType(constantName), enumValue.getConstant(constantName))};
+                    return ${helper.escapeValue(type.getConstantType(constantName), enumValue.getConstant(constantName).orElseThrow())};
                 }
             </#list>
                 default: {
diff --git a/code-generation/language-cs/src/main/resources/templates/cs/io-template.cs.ftlh b/code-generation/language-cs/src/main/resources/templates/cs/io-template.cs.ftlh
new file mode 100644
index 0000000..346eb90
--- /dev/null
+++ b/code-generation/language-cs/src/main/resources/templates/cs/io-template.cs.ftlh
@@ -0,0 +1,299 @@
+<#--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<#-- Prevent freemarker from escaping stuff -->
+<#outputformat "undefined">
+<#-- Declare the name and type of variables passed in to the template -->
+<#-- @ftlvariable name="languageName" type="java.lang.String" -->
+<#-- @ftlvariable name="protocolName" type="java.lang.String" -->
+<#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
+<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.cs.CsLanguageTemplateHelper" -->
+<#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
+<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/model/io/${type.name}.cs
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Code generated by code-generation. DO NOT EDIT.
+
+<#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
+<#if type.parserArguments.isPresent()><#assign parserArguments=type.allParserArguments.orElseThrow()></#if>
+public class ${type.name}IO implements MessageInput<${type.name}> {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(${type.name}IO.class);
+
+<#-- The parse and serialize methods here are just proxies for forwardning the requests to static counterparts -->
+<#if !type.isDiscriminatedChildTypeDefinition()>
+    @Override
+    public ${type.name} parse(ReadBuffer readBuffer, Object... args) throws ParseException {
+        <#if parserArguments?has_content>
+        if((args == null) || (args.length != ${parserArguments?size})) {
+            throw new PlcRuntimeException("Wrong number of arguments, expected ${parserArguments?size}, but got " + args.length);
+        }
+            <#list parserArguments as parserArgument>
+        ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name};
+        if(args[${parserArgument?index}] instanceof ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}) {
+            ${parserArgument.name} = (${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}) args[${parserArgument?index}];
+            <#if helper.isSimpleTypeReference(parserArgument.type)>
+        } else if (args[${parserArgument?index}] instanceof String) {
+            ${parserArgument.name} = ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}.valueOf((String) args[${parserArgument?index}]);
+            </#if>
+        } else {
+            throw new PlcRuntimeException("Argument ${parserArgument?index} expected to be of type ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} or a string which is parseable but was " + args[${parserArgument?index}].getClass().getName());
+        }
+            </#list>
+        </#if>
+        return ${type.name}IO.staticParse(readBuffer<#if parserArguments?has_content>, <#list parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
+    }
+
+<#else>
+    @Override
+    public ${type.name} parse(ReadBuffer readBuffer, Object... args) throws ParseException {
+        return (${type.name}) new ${type.parentType.name}IO().parse(readBuffer, args);
+    }
+
+</#if>
+<#-- Here come the actual parse and serialize methods that actually do the parsing and serlaizing -->
+    <#assign hasParserArguments=parserArguments?has_content/>
+    <#assign parserArgumentList><#if hasParserArguments><#list parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+    public static ${type.name}<#if type.isDiscriminatedChildTypeDefinition()>Builder</#if> staticParse(ReadBuffer readBuffer<#if hasParserArguments>, ${parserArgumentList}</#if>) throws ParseException {
+        readBuffer.pullContext("${type.name}");
+        int startPos = readBuffer.getPos();
+        int curPos;
+<#list type.fields as field>
+<#switch field.typeName>
+    <#case "array">
+        <#assign arrayField = field.asArrayField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign namedField = field.asNamedField().orElseThrow()>
+
+        <#if typedField.type.isByteBased()>
+            <#if !field.isCountArrayField() && !field.isLengthArrayField()>
+        throw new ParseException("array fields of type byte only support 'count' and 'length' loop-types.");
+            </#if>
+        byte[] ${namedField.name} = readBuffer.readByteArray("${namedField.name}", (int) ${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
+        <#else>
+        <#-- If this is a count array, we can directly initialize an array with the given size -->
+            <#if field.isCountArrayField()>
+        List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> ${arrayField.name} = readCountArrayField("${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, ${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
+        <#-- In all other cases do we have to work with a list, that is later converted to an array -->
+            <#else>
+            <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
+                <#if field.isLengthArrayField()>
+        List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> ${arrayField.name} = readLengthArrayField("${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, ${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
+            <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
+                <#elseif field.isTerminatedArrayField()>
+        List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> ${arrayField.name} = readTerminatedArrayField("${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, () -> ((boolean) (${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}))${helper.getFieldOptions(typedField, parserArguments)});
+                </#if>
+            </#if>
+        </#if>
+        <#break>
+    <#case "assert">
+        <#assign assertField = field.asAssertField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign namedField = field.asNamedField().orElseThrow()>
+
+        ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}, ${helper.toParseExpression(assertField, assertField.type, assertField.conditionExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
+        <#break>
+    <#case "checksum">
+        <#assign checksumField = field.asChecksumField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign namedField = field.asNamedField().orElseThrow()>
+
+        ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}, ${helper.toParseExpression(checksumField, checksumField.type, checksumField.checksumExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
+        <#break>
+    <#case "const">
+        <#assign constField = field.asConstField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign namedField = field.asNamedField().orElseThrow()>
+
+        ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}, ${type.name}.${namedField.name?upper_case}${helper.getFieldOptions(typedField, parserArguments)});
+        <#break>
+    <#case "discriminator">
+        <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign namedField = field.asNamedField().orElseThrow()>
+
+        ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)});
+        <#break>
+    <#case "enum">
+        <#assign enumField = field.asEnumField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign namedField = field.asNamedField().orElseThrow()>
+
+        ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", "${helper.getTypeDefinitionForTypeReference(enumField.type).name}", readEnum(${helper.getTypeDefinitionForTypeReference(enumField.type).name}::firstEnumForField${enumField.fieldName?cap_first}, ${helper.getDataReaderCall(helper.getEnumFieldTypeReference(enumField.type, enumField.fieldName))})${helper.getFieldOptions(typedField, parserArguments)});
+        <#break>
+    <#case "implicit">
+        <#assign implicitField = field.asImplicitField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign namedField = field.asNamedField().orElseThrow()>
+
+        ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)});
+        <#break>
+    <#case "manualArray">
+        <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign namedField = field.asNamedField().orElseThrow()>
+
+        <#if manualArrayField.type.isByteBased()>
+        byte[] ${namedField.name} = readManualByteArrayField("${namedField.name}", readBuffer, () -> (boolean) (${helper.toParseExpression(manualArrayField, helper.boolTypeReference, manualArrayField.loopExpression, parserArguments)}), () -> (${helper.getLanguageTypeNameForField(manualArrayField)}) (${helper.toParseExpression(manualArrayField, manualArrayField.type, manualArrayField.parseExpression, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
+        <#else>
+        List<${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}> ${namedField.name} = readManualArrayField("${namedField.name}", readBuffer, () -> (boolean) (${helper.toParseExpression(manualArrayField, helper.boolTypeReference, manualArrayField.loopExpression, parserArguments)}), () -> (${helper.getLanguageTypeNameForField(manualArrayField)}) (${helper.toParseExpression(manualArrayField, manualArrayField.type, manualArrayField.parseExpression, parserArguments)})${helper [...]
+        </#if>
+        <#break>
+    <#case "manual">
+        <#assign manualField = field.asManualField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign namedField = field.asNamedField().orElseThrow()>
+
+        ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = readManualField("${namedField.name}", readBuffer, () -> (${helper.getLanguageTypeNameForField(manualField)}) (${helper.toParseExpression(manualField, manualField.type, manualField.parseExpression, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
+        <#break>
+    <#case "optional">
+        <#assign optionalField = field.asOptionalField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign namedField = field.asNamedField().orElseThrow()>
+
+        ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}<#if optionalField.conditionExpression.present>, ${helper.toParseExpression(optionalField, helper.boolTypeReference, optionalField.conditionExpression.get(), parserArguments)}</#if>${helper.getFieldOptions(typedField, parserArguments)});
+        <#break>
+    <#case "padding">
+        <#assign paddingField = field.asPaddingField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
+
+        read${field.typeName?cap_first}Field(${helper.getDataReaderCall(typedField.type)}, (int) (${helper.toParseExpression(paddingField, paddingField.type, paddingField.paddingCondition, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
+        <#break>
+    <#case "reserved">
+        <#assign reservedField = field.asReservedField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+
+        read${field.typeName?cap_first}Field("reserved", ${helper.getDataReaderCall(typedField.type)}, ${helper.getReservedValue(reservedField)}${helper.getFieldOptions(typedField, parserArguments)});
+        <#break>
+    <#case "simple">
+        <#assign simpleField = field.asSimpleField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign namedField = field.asNamedField().orElseThrow()>
+
+        ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = <#if helper.isEnumTypeReference(typedField.type)>readEnumField("${namedField.name}", "${helper.getLanguageTypeNameForField(field)}", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)});<#else>read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)});</#if>
+        <#break>
+    <#case "switch">
+        <#assign switchField = field.asSwitchField().orElseThrow()>
+
+        // Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
+        ${type.name}Builder builder = null;
+        <#list switchField.cases as case>
+            <@compress single_line=true>
+            <#if case.discriminatorValueTerms?has_content>
+                if(
+                <#list case.discriminatorValueTerms as discriminatorValueTerm>
+                    <#assign discriminatorExpression=switchField.discriminatorExpressions[discriminatorValueTerm?index].asLiteral().orElseThrow().asVariableLiteral().orElseThrow()>
+                    <#assign discriminatorType=helper.getDiscriminatorTypes()[discriminatorExpression.discriminatorName]>
+                    EvaluationHelper.equals(
+                    ${helper.toParseExpression(switchField, discriminatorType, discriminatorExpression, parserArguments)},
+                    <#if helper.isEnumTypeReference(discriminatorType)>
+                    ${helper.getLanguageTypeNameForTypeReference(discriminatorType)}.${helper.toParseExpression(switchField, discriminatorType, discriminatorValueTerm, parserArguments)}
+                    <#else>
+                    ${helper.toParseExpression(switchField, discriminatorType, discriminatorValueTerm, parserArguments)}
+                    </#if>
+                    )
+                    <#sep> && </#sep>
+                    </#list>
+                )
+            </#if>{
+            </...@compress>
+            <@compress single_line=true>
+            <#assign hasCaseParseArguments=case.allParserArguments.isPresent() && case.allParserArguments.orElseThrow()?has_content>
+            <#assign caseParseArguments><#if hasCaseParseArguments><#list case.allParserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+            builder = ${case.name}IO.staticParse(readBuffer<#if hasCaseParseArguments>, ${tracer.dive("case parse arguments")} ${caseParseArguments}</#if>);
+            </...@compress>
+        }<#sep> else </#sep>
+        </#list>
+        if (builder == null) {
+            throw new ParseException("Unsupported case for discriminated type");
+        }
+        <#break>
+    <#case "unknown">
+        <#assign unknownField = field.asUnknownField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+
+        read${field.typeName?cap_first}Field("unknown", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)});
+        <#break>
+    <#case "virtual">
+        <#assign virtualField = field.asVirtualField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign namedField = field.asNamedField().orElseThrow()>
+
+        ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field(${helper.getLanguageTypeNameForField(field)}.class, ${helper.toParseExpression(virtualField, virtualField.type, virtualField.valueExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
+        <#break>
+</#switch>
+</#list>
+
+        readBuffer.closeContext("${type.name}");
+        // Create the instance
+        <#if type.isDiscriminatedChildTypeDefinition()>
+        return new ${type.name}Builder(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
+        <#elseif type.isDiscriminatedParentTypeDefinition()>
+        return builder.build(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
+        <#else>
+        return new ${type.name}(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
+        </#if>
+    }
+
+<#if type.isDiscriminatedParentTypeDefinition()>
+    public static interface ${type.name}Builder {
+        ${type.name} build(<#list type.propertyFields as field><#if field.loopType??>List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}><#else>${helper.getLanguageTypeNameForField(field)}</#if> ${field.name}<#sep>, </#sep></#list>);
+    }
+
+</#if>
+<#if type.isDiscriminatedChildTypeDefinition()>
+    public static class ${type.name}Builder implements ${type.parentType.name}IO.${type.parentType.name}Builder {
+        <#if type.propertyFields?has_content>
+            <#list type.propertyFields as field>
+        private final <#if field.loopType?? && field.type.isByteBased()>byte[]<#elseif field.loopType??>List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}><#else>${helper.getLanguageTypeNameForField(field)}</#if> ${field.name};
+            </#list>
+        </#if>
+
+        public ${type.name}Builder(<#list type.propertyFields as field><#if field.loopType?? && field.type.isByteBased()>byte[]<#elseif field.loopType??>List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}><#else>${helper.getLanguageTypeNameForField(field)}</#if> ${field.name}<#sep>, </#sep></#list>) {
+            <#list type.propertyFields as field>
+            this.${field.name} = ${field.name};
+            </#list>
+        }
+
+        public ${type.name} build(<#list type.parentType.asComplexTypeDefinition().orElseThrow().propertyFields as field><#if field.loopType?? && field.type.isByteBased()>byte[]<#elseif field.loopType??>List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}><#else>${helper.getLanguageTypeNameForField(field)}</#if> ${field.name}<#sep>, </#sep></#list>) {
+            return new ${type.name}(<#list type.allPropertyFields as field>${field.name}<#sep>, </#sep></#list>);
+        }
+    }
+
+</#if>
+}
+</#outputformat>
diff --git a/code-generation/language-java/src/main/resources/templates/java/pojo-template.java.ftlh b/code-generation/language-cs/src/main/resources/templates/cs/model-template.cs.ftlh
similarity index 59%
copy from code-generation/language-java/src/main/resources/templates/java/pojo-template.java.ftlh
copy to code-generation/language-cs/src/main/resources/templates/cs/model-template.cs.ftlh
index 07dc000..0616a5b 100644
--- a/code-generation/language-java/src/main/resources/templates/java/pojo-template.java.ftlh
+++ b/code-generation/language-cs/src/main/resources/templates/cs/model-template.cs.ftlh
@@ -22,11 +22,11 @@
 <#-- @ftlvariable name="languageName" type="java.lang.String" -->
 <#-- @ftlvariable name="protocolName" type="java.lang.String" -->
 <#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
-<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.java.JavaLanguageTemplateHelper" -->
+<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.cs.CsLanguageTemplateHelper" -->
 <#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
 <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
 <#-- Declare the name and type of variables declared locally inside the template -->
-${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/${type.name}.java
+${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/model/${type.name}.cs
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -45,31 +45,23 @@ ${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")
  * specific language governing permissions and limitations
  * under the License.
  */
-package ${helper.packageName(protocolName, languageName, outputFlavor)};
-
-import static org.apache.plc4x.java.spi.generation.StaticHelper.*;
-import static org.apache.plc4x.java.spi.codegen.io.DataWriterFactory.*;
-import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*;
-
-import org.apache.plc4x.java.api.value.*;
-import org.apache.plc4x.java.spi.codegen.io.DataWriterComplexDefault;
-import org.apache.plc4x.java.spi.codegen.io.DataWriterEnumDefault;
-import org.apache.plc4x.java.spi.generation.Message;
-import org.apache.plc4x.java.spi.generation.MessageIO;
-import org.apache.plc4x.java.spi.generation.SerializationException;
-import org.apache.plc4x.java.spi.generation.WriteBuffer;
-import org.apache.plc4x.java.spi.generation.WriteBufferBoxBased;
-import org.apache.plc4x.java.spi.generation.WithReaderWriterArgs;
-
-import java.time.*;
-import java.util.*;
-import java.math.BigInteger;
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
 
 // Code generated by code-generation. DO NOT EDIT.
 
 <#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
 <#if type.parserArguments.isPresent()><#assign parserArguments=type.parserArguments.orElseThrow()></#if>
-public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${type.name}<#if type.parentType??> extends ${type.parentType.name}</#if> implements Message {
+namespace org.apache.plc4net.drivers.${protocolName?replace("-", "")}.${outputFlavor?replace("-", "")}.model
+{
+
+    public<#if helper.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${type.name}<#if type.parentType??> : ${type.parentType.name}</#if>
+    {
 
 <#--
     If this is a discriminated child type, we need to generate methods for accessing it's discriminator
@@ -77,22 +69,12 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
 -->
 <#if type.isDiscriminatedChildTypeDefinition()>
     <#assign discriminatedChildType = type.asDiscriminatedComplexTypeDefinition().orElseThrow()>
-    // Accessors for discriminator values.
+        // Accessors for discriminator values.
     <#list discriminatedChildType.getDiscriminatorMap() as discriminatorName, discriminatorValue>
         <#-- If the discriminator name matches that of another field, suppress the methods generation -->
         <#if !discriminatedChildType.isNonDiscriminatorField(discriminatorName)><#--&& !discriminatedChildType.isParserArgument(discriminatorName)-->
             <#assign discriminatorType = helper.getDiscriminatorTypes()[discriminatorName]>
-    public ${helper.getLanguageTypeNameForTypeReference(discriminatorType)} get${discriminatorName?cap_first}() {
-            <#if discriminatorValue??>
-                <#if helper.isEnumTypeReference(discriminatorType)>
-        return ${helper.getLanguageTypeNameForTypeReference(discriminatorType)}.${helper.toParseExpression(null, discriminatorType, discriminatorValue, parserArguments)};
-                <#else>
-        return ${helper.toParseExpression(null, discriminatorType, discriminatorValue, parserArguments)};
-                </#if>
-            <#else>
-        return ${helper.getNullValueForTypeReference(discriminatorType)};
-            </#if>
-    }
+        public override ${helper.getLanguageTypeNameForTypeReference(discriminatorType)} ${discriminatorName?cap_first} => <#if discriminatorValue??><#if helper.isEnumTypeReference(discriminatorType)>${helper.getLanguageTypeNameForTypeReference(discriminatorType)}.${helper.toParseExpression(null, discriminatorType, discriminatorValue, parserArguments)}<#else>${helper.toParseExpression(null, discriminatorType, discriminatorValue, parserArguments)}</#if><#else>${helper.getNullValueForTypeR [...]
         </#if>
     </#list>
 </#if>
@@ -103,42 +85,43 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
 <#if type.isDiscriminatedParentTypeDefinition()>
     <#assign discriminatedParentType = type>
     <#-- @ftlvariable name="discriminatedParentType" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
-    // Abstract accessors for discriminator values.
+        // Abstract accessors for discriminator values.
     <#list helper.discriminatorTypes as discriminatorName, discriminatorType>
         <#-- If the discriminator name matches that of another field, suppress the methods generation -->
         <#if !type.isNonDiscriminatorField(discriminatorName)><#-- && !type.isParserArgument(discriminatorName)-->
-    public abstract ${helper.getLanguageTypeNameForTypeReference(discriminatorType)} get${discriminatorName?cap_first}();
+        public abstract ${helper.getLanguageTypeNameForTypeReference(discriminatorType)} ${discriminatorName?cap_first} { get; }
         </#if>
     </#list>
 </#if>
 <#-- If the current type contains "const" fields, generate some java constants for holing their values -->
 <#if type.constFields?has_content>
 
-    // Constant values.
+        // Constant values.
 <#list type.constFields as field>
-    public static final ${helper.getLanguageTypeNameForField(field)} ${field.name?upper_case} = ${helper.toParseExpression(field, field.type, field.referenceValue, parserArguments)};
+        public const ${helper.getLanguageTypeNameForField(field)} ${field.name?upper_case} = ${helper.toParseExpression(field, field.type, field.referenceValue, parserArguments)};
 </#list>
 </#if>
 <#-- Property fields are fields that require a property in the pojo -->
 <#if type.propertyFields?has_content>
 
-    // Properties.
+        // Properties.
 <#list type.propertyFields as field>
-    protected final <#if field.loopType?? && field.type.isByteBased()>byte[]<#elseif field.loopType??>List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}><#else>${helper.getLanguageTypeNameForField(field)}</#if> ${field.name};
+        public ${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name?cap_first} { get; }
 </#list>
 </#if>
 
     <#-- getAllPropertyFields() returns not only the property fields of this type but also of it's parents -->
-    public ${type.name}(<#list type.getAllPropertyFields() as field><#if field.loopType?? && field.type.isByteBased()>byte[]<#elseif field.loopType??>List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}><#else>${helper.getLanguageTypeNameForField(field)}</#if> ${field.name}<#sep>, </#sep></#list>) {
+        public ${type.name}(<#list type.getAllPropertyFields() as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>)
 <#if type.getParentPropertyFields()?has_content>
-        super(<#list type.getParentPropertyFields() as field>${field.name}<#sep>, </#sep></#list>);
+            : base(<#list type.getParentPropertyFields() as field>${field.name}<#sep>, </#sep></#list>)
 </#if>
+        {
 <#list type.propertyFields as field>
-        this.${field.name} = ${field.name};
+            ${field.name?cap_first} = ${field.name};
 </#list>
-    }
+        }
 
-<#list type.abstractFields as field>
+<#--list type.abstractFields as field>
     public abstract <#if field.loopType?? && field.type.isByteBased()>byte[]<#elseif field.loopType??>List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}><#else>${helper.getLanguageTypeNameForField(field)}</#if> get${field.asNamedField().orElseThrow().name?cap_first}();
 
 </#list>
@@ -233,7 +216,7 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                         <#assign namedField = field.asNamedField().orElseThrow()>
 
                         // Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
-                        <#-- Implicit field values might be used in expressions, in order to avoid problems, we generate a temporary variable with the given name. -->
+                        <#- Implicit field values might be used in expressions, in order to avoid problems, we generate a temporary variable with the given name. ->
                         ${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(implicitField, implicitField.type, implicitField.serializeExpression, parserArguments)});
                         writeImplicitField("${namedField.name}", ${implicitField.name}, ${helper.getDataWriterCall(typedField.type, namedField.name)});
                         <#break>
@@ -311,219 +294,174 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
         return getLengthInBits() / 8;
     }
 
-    @Override
-    public int getLengthInBits() {
-        int lengthInBits = <#if type.parentType??>super.getLengthInBits()<#else>0</#if>;
-        ${type.name} _value  = this;
-<#list type.fields as field>
-<#switch field.typeName>
-    <#case "array">
-        <#assign arrayField = field.asArrayField().orElseThrow()>
-
-        // Array field
-        if(${arrayField.name} != null) {
-        <#if helper.isSimpleTypeReference(arrayField.type)>
-            <#assign simpleTypeReference = arrayField.type.asSimpleTypeReference().orElseThrow()>
-            lengthInBits += ${simpleTypeReference.sizeInBits} * ${arrayField.name}.<#if arrayField.type.isByteBased()>length<#else>size()</#if>;
-        <#elseif arrayField.isCountArrayField()>
-            int i=0;
-            <#assign complexTypeReference = arrayField.type.asComplexTypeReference().orElseThrow()>
-            for(${complexTypeReference.name} element : ${arrayField.name}) {
-                boolean last = ++i >= ${arrayField.name}.size();
-                lengthInBits += element.getLengthInBits();
-            }
-        <#else>
-            for(Message element : ${arrayField.name}) {
-                lengthInBits += element.getLengthInBits();
+        @Override
+        public int getLengthInBits() {
+            int lengthInBits = <#if type.parentType??>super.getLengthInBits()<#else>0</#if>;
+            ${type.name} _value  = this;
+    <#list type.fields as field>
+    <#switch field.typeName>
+        <#case "array">
+            <#assign arrayField = field.asArrayField().orElseThrow()>
+
+            // Array field
+            if(${arrayField.name} != null) {
+            <#if helper.isSimpleTypeReference(arrayField.type)>
+                <#assign simpleTypeReference = arrayField.type.asSimpleTypeReference().orElseThrow()>
+                lengthInBits += ${simpleTypeReference.sizeInBits} * ${arrayField.name}.<#if arrayField.type.isByteBased()>length<#else>size()</#if>;
+            <#elseif arrayField.isCountArrayField()>
+                int i=0;
+                <#assign complexTypeReference = arrayField.type.asComplexTypeReference().orElseThrow()>
+                for(${complexTypeReference.name} element : ${arrayField.name}) {
+                    boolean last = ++i >= ${arrayField.name}.size();
+                    lengthInBits += element.getLengthInBits();
+                }
+            <#else>
+                for(Message element : ${arrayField.name}) {
+                    lengthInBits += element.getLengthInBits();
+                }
+            </#if>
             }
-        </#if>
-        }
-        <#break>
-    <#case "checksum">
-        <#assign checksumField = field.asChecksumField().orElseThrow()>
-        <#assign typedField = field.asTypedField().orElseThrow()>
-        <#assign simpleTypeReference = typedField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Checksum Field (checksum)
-        lengthInBits += ${simpleTypeReference.sizeInBits};
-        <#break>
-    <#case "const">
-        <#assign constField = field.asConstField().orElseThrow()>
-        <#assign typedField = field.asTypedField().orElseThrow()>
-
-        // Const Field (${constField.name})
-        <#if helper.isSimpleTypeReference(typedField.type)>
-        <#assign simpleTypeReference = typedField.type.asSimpleTypeReference().orElseThrow()>
-        lengthInBits += ${simpleTypeReference.sizeInBits};
-        <#else>
-        lengthInBits += ${helper.getEnumBaseTypeReference(typedField.type).sizeInBits};
-        </#if>
-        <#break>
-    <#case "discriminator">
-        <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
-
-        // Discriminator Field (${discriminatorField.name})
-        <#if helper.isSimpleTypeReference(discriminatorField.type)>
-            <#assign simpleTypeReference = discriminatorField.type.asSimpleTypeReference().orElseThrow()>
-            <#if simpleTypeReference.isVstringTypeReference()>
-                <#assign vstringTypeReference = simpleTypeReference.asVstringTypeReference().orElseThrow()>
-        lengthInBits += ${helper.toSerializationExpression(discriminatorField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)};
+            <#break>
+        <#case "checksum">
+            <#assign checksumField = field.asChecksumField().orElseThrow()>
+            <#assign typedField = field.asTypedField().orElseThrow()>
+            <#assign simpleTypeReference = typedField.type.asSimpleTypeReference().orElseThrow()>
+
+            // Checksum Field (checksum)
+            lengthInBits += ${simpleTypeReference.sizeInBits};
+            <#break>
+        <#case "const">
+            <#assign constField = field.asConstField().orElseThrow()>
+            <#assign typedField = field.asTypedField().orElseThrow()>
+
+            // Const Field (${constField.name})
+            <#if helper.isSimpleTypeReference(typedField.type)>
+            <#assign simpleTypeReference = typedField.type.asSimpleTypeReference().orElseThrow()>
+            lengthInBits += ${simpleTypeReference.sizeInBits};
             <#else>
-        lengthInBits += ${simpleTypeReference.sizeInBits};
+            lengthInBits += ${helper.getEnumBaseTypeReference(typedField.type).sizeInBits};
             </#if>
-        <#elseif helper.isEnumField(field)>
-            lengthInBits += ${helper.getEnumBaseTypeReference(discriminatorField.type).sizeInBits};
-        <#else>
-            lengthInBits += ${discriminatorField.name}.getLengthInBits();
-        </#if>
-        <#break>
-    <#case "enum">
-        <#assign enumField = field.asEnumField().orElseThrow()>
-
-        // Enum Field (${enumField.name})
-        lengthInBits += ${helper.getEnumBaseTypeReference(enumField.type).sizeInBits};
-        <#break>
-    <#case "implicit">
-        <#assign implicitField = field.asImplicitField().orElseThrow()>
-        <#assign simpleTypeReference = implicitField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Implicit Field (${implicitField.name})
-        lengthInBits += ${simpleTypeReference.sizeInBits};
-        <#break>
-    <#case "manualArray">
-        <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
-
-        // Manual Array Field (${manualArrayField.name})
-        lengthInBits += ${helper.toParseExpression(manualArrayField, helper.intTypeReference, manualArrayField.lengthExpression, parserArguments)} * 8;
-        <#break>
-    <#case "manual">
-        <#assign manualField = field.asManualField().orElseThrow()>
-
-        // Manual Field (${manualField.name})
-        lengthInBits += ${helper.toParseExpression(manualField, helper.intTypeReference, manualField.lengthExpression, parserArguments)} * 8;
-        <#break>
-    <#case "optional">
-        <#assign optionalField = field.asOptionalField().orElseThrow()>
-
-        // Optional Field (${optionalField.name})
-        if(${optionalField.name} != null) {
-        <#if helper.isSimpleTypeReference(optionalField.type)>
-            <#assign simpleTypeReference = optionalField.type.asSimpleTypeReference().orElseThrow()>
-            <#if simpleTypeReference.isVstringTypeReference()>
-                <#assign vstringTypeReference = simpleTypeReference.asVstringTypeReference().orElseThrow()>
-            lengthInBits += ${helper.toSerializationExpression(optionalField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)};
+            <#break>
+        <#case "discriminator">
+            <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
+
+            // Discriminator Field (${discriminatorField.name})
+            <#if helper.isSimpleTypeReference(discriminatorField.type)>
+                <#assign simpleTypeReference = discriminatorField.type.asSimpleTypeReference().orElseThrow()>
+                <#if simpleTypeReference.isVstringTypeReference()>
+                    <#assign vstringTypeReference = simpleTypeReference.asVstringTypeReference().orElseThrow()>
+            lengthInBits += ${helper.toSerializationExpression(discriminatorField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)};
+                <#else>
+            lengthInBits += ${simpleTypeReference.sizeInBits};
+                </#if>
+            <#elseif helper.isEnumField(field)>
+                lengthInBits += ${helper.getEnumBaseTypeReference(discriminatorField.type).sizeInBits};
             <#else>
+                lengthInBits += ${discriminatorField.name}.getLengthInBits();
+            </#if>
+            <#break>
+        <#case "enum">
+            <#assign enumField = field.asEnumField().orElseThrow()>
+
+            // Enum Field (${enumField.name})
+            lengthInBits += ${helper.getEnumBaseTypeReference(enumField.type).sizeInBits};
+            <#break>
+        <#case "implicit">
+            <#assign implicitField = field.asImplicitField().orElseThrow()>
+            <#assign simpleTypeReference = implicitField.type.asSimpleTypeReference().orElseThrow()>
+
+            // Implicit Field (${implicitField.name})
             lengthInBits += ${simpleTypeReference.sizeInBits};
+            <#break>
+        <#case "manualArray">
+            <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
+
+            // Manual Array Field (${manualArrayField.name})
+            lengthInBits += ${helper.toParseExpression(manualArrayField, helper.intTypeReference, manualArrayField.lengthExpression, parserArguments)} * 8;
+            <#break>
+        <#case "manual">
+            <#assign manualField = field.asManualField().orElseThrow()>
+
+            // Manual Field (${manualField.name})
+            lengthInBits += ${helper.toParseExpression(manualField, helper.intTypeReference, manualField.lengthExpression, parserArguments)} * 8;
+            <#break>
+        <#case "optional">
+            <#assign optionalField = field.asOptionalField().orElseThrow()>
+
+            // Optional Field (${optionalField.name})
+            if(${optionalField.name} != null) {
+            <#if helper.isSimpleTypeReference(optionalField.type)>
+                <#assign simpleTypeReference = optionalField.type.asSimpleTypeReference().orElseThrow()>
+                <#if simpleTypeReference.isVstringTypeReference()>
+                    <#assign vstringTypeReference = simpleTypeReference.asVstringTypeReference().orElseThrow()>
+                lengthInBits += ${helper.toSerializationExpression(optionalField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)};
+                <#else>
+                lengthInBits += ${simpleTypeReference.sizeInBits};
+                </#if>
+            <#elseif helper.isEnumField(field)>
+                lengthInBits += ${helper.getEnumBaseTypeReference(optionalField.type).sizeInBits};
+            <#else>
+                lengthInBits += ${optionalField.name}.getLengthInBits();
             </#if>
-        <#elseif helper.isEnumField(field)>
-            lengthInBits += ${helper.getEnumBaseTypeReference(optionalField.type).sizeInBits};
-        <#else>
-            lengthInBits += ${optionalField.name}.getLengthInBits();
-        </#if>
-        }
-        <#break>
-    <#case "padding">
-        <#assign paddingField = field.asPaddingField().orElseThrow()>
-        <#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Padding Field (padding)
-        <#-- We're replacing the "lastItem" with 'false' here as the item itself can't know if it is the last -->
-        int _timesPadding = (int) (${helper.toParseExpression(paddingField, helper.intTypeReference, paddingField.paddingCondition, parserArguments)});
-        while (_timesPadding-- > 0) {
+            }
+            <#break>
+        <#case "padding">
+            <#assign paddingField = field.asPaddingField().orElseThrow()>
+            <#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
+
+            // Padding Field (padding)
+            <#- We're replacing the "lastItem" with 'false' here as the item itself can't know if it is the last ->
+            int _timesPadding = (int) (${helper.toParseExpression(paddingField, helper.intTypeReference, paddingField.paddingCondition, parserArguments)});
+            while (_timesPadding-- > 0) {
+                lengthInBits += ${simpleTypeReference.sizeInBits};
+            }
+            <#break>
+        <#case "reserved">
+            <#assign reservedField = field.asReservedField().orElseThrow()>
+            <#assign simpleTypeReference = reservedField.type.asSimpleTypeReference().orElseThrow()>
+
+            // Reserved Field (reserved)
             lengthInBits += ${simpleTypeReference.sizeInBits};
-        }
-        <#break>
-    <#case "reserved">
-        <#assign reservedField = field.asReservedField().orElseThrow()>
-        <#assign simpleTypeReference = reservedField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Reserved Field (reserved)
-        lengthInBits += ${simpleTypeReference.sizeInBits};
-        <#break>
-    <#case "simple">
-        <#assign simpleField = field.asSimpleField().orElseThrow()>
-
-        // Simple field (${simpleField.name})
-        <#if simpleField.type.isSimpleTypeReference()>
-            <#assign simpleTypeReference = simpleField.type.asSimpleTypeReference().orElseThrow()>
-            <#if simpleTypeReference.isVstringTypeReference()>
-                <#assign vstringTypeReference = simpleTypeReference.asVstringTypeReference().orElseThrow()>
-        lengthInBits += ${helper.toSerializationExpression(simpleField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)};
+            <#break>
+        <#case "simple">
+            <#assign simpleField = field.asSimpleField().orElseThrow()>
+
+            // Simple field (${simpleField.name})
+            <#if simpleField.type.isSimpleTypeReference()>
+                <#assign simpleTypeReference = simpleField.type.asSimpleTypeReference().orElseThrow()>
+                <#if simpleTypeReference.isVstringTypeReference()>
+                    <#assign vstringTypeReference = simpleTypeReference.asVstringTypeReference().orElseThrow()>
+            lengthInBits += ${helper.toSerializationExpression(simpleField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)};
+                <#else>
+            lengthInBits += ${simpleTypeReference.sizeInBits};
+                </#if>
+            <#elseif helper.isEnumField(field)>
+            lengthInBits += ${helper.getEnumBaseTypeReference(simpleField.type).sizeInBits};
             <#else>
-        lengthInBits += ${simpleTypeReference.sizeInBits};
+            lengthInBits += ${simpleField.name}.getLengthInBits();
             </#if>
-        <#elseif helper.isEnumField(field)>
-        lengthInBits += ${helper.getEnumBaseTypeReference(simpleField.type).sizeInBits};
-        <#else>
-        lengthInBits += ${simpleField.name}.getLengthInBits();
-        </#if>
-        <#break>
-    <#case "switch">
-        <#assign switchField = field.asSwitchField().orElseThrow()>
-
-        // Length of sub-type elements will be added by sub-type...
-        <#break>
-    <#case "unknown">
-        <#assign unknownField = field.asUnknownField().orElseThrow()>
-        <#assign simpleTypeReference = unknownField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Unknown field
-        lengthInBits += ${simpleTypeReference.sizeInBits};
-    <#case "virtual">
-        <#assign virtualField = field>
-
-        // A virtual field doesn't have any in- or output.
-        <#break>
-</#switch>
-</#list>
+            <#break>
+        <#case "switch">
+            <#assign switchField = field.asSwitchField().orElseThrow()>
 
-        return lengthInBits;
-    }
+            // Length of sub-type elements will be added by sub-type...
+            <#break>
+        <#case "unknown">
+            <#assign unknownField = field.asUnknownField().orElseThrow()>
+            <#assign simpleTypeReference = unknownField.type.asSimpleTypeReference().orElseThrow()>
 
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (!(o instanceof ${type.name})) {
-            return false;
-        }
-        ${type.name} that = (${type.name}) o;
-        return
-            <#if type.propertyFields?has_content>
-            <#list type.propertyFields as field>
-            (get${field.name?cap_first}() == that.get${field.name?cap_first}()) &&
-            </#list>
-            </#if>
-            <#if type.parentType??>
-            super.equals(that) &&
-            </#if>
-            true;
-    }
+            // Unknown field
+            lengthInBits += ${simpleTypeReference.sizeInBits};
+        <#case "virtual">
+            <#assign virtualField = field>
 
-    @Override
-    public int hashCode() {
-        return Objects.hash(
-            <#if type.parentType??>
-            super.hashCode()<#if type.propertyFields?has_content>,</#if>
-            </#if>
-            <#if type.propertyFields?has_content>
-            <#list type.propertyFields as field>
-            get${field.name?cap_first}()<#sep>,</#sep>
-            </#list>
-            </#if>
-        );
-    }
+            // A virtual field doesn't have any in- or output.
+            <#break>
+    </#switch>
+    </#list>
 
-    @Override
-    public String toString() {
-        WriteBufferBoxBased writeBufferBoxBased = new WriteBufferBoxBased(true, true);
-        try {
-            serialize(writeBufferBoxBased);
-        } catch (SerializationException e) {
-            throw new RuntimeException(e);
-        }
-        return "\n" + writeBufferBoxBased.getBox().toString()+ "\n";
+            return lengthInBits;
+        }-->
     }
 }
 </#outputformat>
\ No newline at end of file
diff --git a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
index 4c0989a..d6114f1 100644
--- a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
+++ b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
@@ -63,7 +63,7 @@ public class JavaLanguageOutput extends FreemarkerLanguageOutput {
     @Override
     protected List<Template> getComplexTypeTemplates(Configuration freemarkerConfiguration) throws IOException {
         return Arrays.asList(
-            freemarkerConfiguration.getTemplate("templates/java/pojo-template.java.ftlh"),
+            freemarkerConfiguration.getTemplate("templates/java/model-template.java.ftlh"),
             freemarkerConfiguration.getTemplate("templates/java/io-template.java.ftlh"));
     }
 
diff --git a/code-generation/language-java/src/main/resources/templates/java/pojo-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh
similarity index 100%
rename from code-generation/language-java/src/main/resources/templates/java/pojo-template.java.ftlh
rename to code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh
diff --git a/code-generation/pom.xml b/code-generation/pom.xml
index b558de8..4f55a63 100644
--- a/code-generation/pom.xml
+++ b/code-generation/pom.xml
@@ -17,7 +17,8 @@
   specific language governing permissions and limitations
   under the License.
   -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
   <modelVersion>4.0.0</modelVersion>
 
@@ -39,26 +40,30 @@
     <module>protocol-test</module>
 
     <module>language-java</module>
-    <!--module>language-java-old</module-->
   </modules>
 
   <profiles>
-  <!-- Build PLC4X including the C modules -->
-  <profile>
-    <id>with-c</id>
-    <modules>
-      <module>language-c</module>
-    </modules>
-  </profile>
+    <profile>
+      <id>with-c</id>
+      <modules>
+        <module>language-c</module>
+      </modules>
+    </profile>
 
-  <profile>
-    <id>with-go</id>
-    <modules>
-      <module>language-go</module>
-    </modules>
-  </profile>
+    <profile>
+      <id>with-dotnet</id>
+      <modules>
+        <module>language-cs</module>
+      </modules>
+    </profile>
 
-</profiles>
+    <profile>
+      <id>with-go</id>
+      <modules>
+        <module>language-go</module>
+      </modules>
+    </profile>
+  </profiles>
 
   <dependencies>
     <!-- JUnit 5 Support -->
diff --git a/plc4go/internal/plc4go/knxnetip/readwrite/model/KnxManufacturer.go b/plc4go/internal/plc4go/knxnetip/readwrite/model/KnxManufacturer.go
index afc995e..66cb884 100644
--- a/plc4go/internal/plc4go/knxnetip/readwrite/model/KnxManufacturer.go
+++ b/plc4go/internal/plc4go/knxnetip/readwrite/model/KnxManufacturer.go
@@ -605,8 +605,9 @@ const (
 	KnxManufacturer_M_GOLDMEDAL                                          KnxManufacturer = 567
 	KnxManufacturer_M_CannX                                              KnxManufacturer = 568
 	KnxManufacturer_M_EGI___EARTH_GOODNESS                               KnxManufacturer = 569
-	KnxManufacturer_M_ABB___RESERVED                                     KnxManufacturer = 570
-	KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED                    KnxManufacturer = 571
+	KnxManufacturer_M_VIEGA_GMBH_AND_CO__KG                              KnxManufacturer = 570
+	KnxManufacturer_M_ABB___RESERVED                                     KnxManufacturer = 571
+	KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED                    KnxManufacturer = 572
 )
 
 var KnxManufacturerValues []KnxManufacturer
@@ -1184,6 +1185,7 @@ func init() {
 		KnxManufacturer_M_GOLDMEDAL,
 		KnxManufacturer_M_CannX,
 		KnxManufacturer_M_EGI___EARTH_GOODNESS,
+		KnxManufacturer_M_VIEGA_GMBH_AND_CO__KG,
 		KnxManufacturer_M_ABB___RESERVED,
 		KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED,
 	}
@@ -3289,10 +3291,14 @@ func (e KnxManufacturer) Number() uint16 {
 		}
 	case 570:
 		{ /* '570' */
-			return 43954
+			return 628
 		}
 	case 571:
 		{ /* '571' */
+			return 43954
+		}
+	case 572:
+		{ /* '572' */
 			return 43959
 		}
 	case 58:
@@ -5595,10 +5601,14 @@ func (e KnxManufacturer) Name() string {
 		}
 	case 570:
 		{ /* '570' */
-			return "ABB - reserved"
+			return "Viega GmbH & Co. KG"
 		}
 	case 571:
 		{ /* '571' */
+			return "ABB - reserved"
+		}
+	case 572:
+		{ /* '572' */
 			return "Busch-Jaeger Elektro - reserved"
 		}
 	case 58:
@@ -6851,8 +6861,10 @@ func KnxManufacturerByValue(value uint16) KnxManufacturer {
 	case 57:
 		return KnxManufacturer_M_ORAS
 	case 570:
-		return KnxManufacturer_M_ABB___RESERVED
+		return KnxManufacturer_M_VIEGA_GMBH_AND_CO__KG
 	case 571:
+		return KnxManufacturer_M_ABB___RESERVED
+	case 572:
 		return KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED
 	case 58:
 		return KnxManufacturer_M_DAETWYLER
@@ -8000,6 +8012,8 @@ func KnxManufacturerByName(value string) KnxManufacturer {
 		return KnxManufacturer_M_EGI___EARTH_GOODNESS
 	case "M_ORAS":
 		return KnxManufacturer_M_ORAS
+	case "M_VIEGA_GMBH_AND_CO__KG":
+		return KnxManufacturer_M_VIEGA_GMBH_AND_CO__KG
 	case "M_ABB___RESERVED":
 		return KnxManufacturer_M_ABB___RESERVED
 	case "M_BUSCH_JAEGER_ELEKTRO___RESERVED":
@@ -9180,6 +9194,8 @@ func (e KnxManufacturer) name() string {
 		return "M_EGI___EARTH_GOODNESS"
 	case KnxManufacturer_M_ORAS:
 		return "M_ORAS"
+	case KnxManufacturer_M_VIEGA_GMBH_AND_CO__KG:
+		return "M_VIEGA_GMBH_AND_CO__KG"
 	case KnxManufacturer_M_ABB___RESERVED:
 		return "M_ABB___RESERVED"
 	case KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED:
diff --git a/sandbox/plc4net/api/api/value/IPlcValue.cs b/sandbox/plc4net/api/api/value/IPlcValue.cs
index a6682b9..b1931bd 100644
--- a/sandbox/plc4net/api/api/value/IPlcValue.cs
+++ b/sandbox/plc4net/api/api/value/IPlcValue.cs
@@ -75,7 +75,7 @@ namespace org.apache.plc4net.api.value
         bool IsList();
         int GetLength();
         IPlcValue GetIndex(int index);
-        IPlcValue[] GetList();
+        List<IPlcValue> GetList();
 
         // Struct Methods
         bool IsStruct();
diff --git a/sandbox/plc4net/drivers/knxnetip-test/resources/protocols/knxnetip/ParserSerializerTestsuite.xml b/sandbox/plc4net/drivers/knxnetip-test/resources/protocols/knxnetip/ParserSerializerTestsuite.xml
index 2eae8b6..666ca62 100644
--- a/sandbox/plc4net/drivers/knxnetip-test/resources/protocols/knxnetip/ParserSerializerTestsuite.xml
+++ b/sandbox/plc4net/drivers/knxnetip-test/resources/protocols/knxnetip/ParserSerializerTestsuite.xml
@@ -17,10 +17,14 @@
   specific language governing permissions and limitations
   under the License.
   -->
-<test:testsuite xmlns:test="https://plc4x.apache.org/schemas/parser-serializer-testsuite.xsd" bigEndian="true">
+<test:testsuite xmlns:test="https://plc4x.apache.org/schemas/parser-serializer-testsuite.xsd"
+                byteOrder="BIG_ENDIAN">
 
   <name>KNXNet/IP</name>
 
+  <protocolName>knxnetip</protocolName>
+  <outputFlavor>read-write</outputFlavor>
+
   <!--testcase>
     <name>Causes Failure 1</name>
     <raw>0610042000180404ce002b0703010404025002bab8b838bb</raw>
@@ -49,7 +53,7 @@
         </tunnelingRequestDataBlock>
         <cemi className="org.apache.plc4x.java.knxnetip.readwrite.CEMIBusmonInd">
           <additionalInformationLength>7</additionalInformationLength>
-          <additionalInformation>
+          <additionalInformation isList="true">
             <additionalInformation className="org.apache.plc4x.java.knxnetip.readwrite.CEMIAdditionalInformationBusmonitorInfo">
               <frameErrorFlag>false</frameErrorFlag>
               <bitErrorFlag>false</bitErrorFlag>
@@ -89,7 +93,7 @@
         </tunnelingRequestDataBlock>
         <cemi className="org.apache.plc4x.java.knxnetip.readwrite.CEMIBusmonInd">
           <additionalInformationLength>7</additionalInformationLength>
-          <additionalInformation>
+          <additionalInformation isList="true">
             <additionalInformation className="org.apache.plc4x.java.knxnetip.readwrite.CEMIAdditionalInformationBusmonitorInfo">
               <frameErrorFlag>false</frameErrorFlag>
               <bitErrorFlag>false</bitErrorFlag>
@@ -116,73 +120,129 @@
 
   <testcase>
     <name>Search Request</name>
-    <raw>06100201000e0801c0a82a46ef8e</raw>
+    <raw>06100201000e0801c0a82ac8d6b4</raw>
     <root-type>KnxNetIpMessage</root-type>
     <xml>
-      <SearchRequest className="org.apache.plc4x.java.knxnetip.readwrite.SearchRequest">
-        <hpaiIDiscoveryEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIDiscoveryEndpoint">
-          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
-          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
-            <addr>wKgqRg==</addr>
-          </ipAddress>
-          <ipPort>61326</ipPort>
-        </hpaiIDiscoveryEndpoint>
-      </SearchRequest>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">513</msgType>
+        <totalLength dataType="uint" bitLength="16">14</totalLength>
+        <SearchRequest>
+          <hpaiIDiscoveryEndpoint>
+            <HPAIDiscoveryEndpoint>
+              <structureLength dataType="uint" bitLength="8">8</structureLength>
+              <hostProtocolCode>
+                <HostProtocolCode dataType="uint" bitLength="8" stringRepresentation="IPV4_UDP">1</HostProtocolCode>
+              </hostProtocolCode>
+              <ipAddress>
+                <IPAddress>
+                  <addr dataType="byte" bitLength="32">0xc0a82ac8</addr>
+                </IPAddress>
+              </ipAddress>
+              <ipPort dataType="uint" bitLength="16">54964</ipPort>
+            </HPAIDiscoveryEndpoint>
+          </hpaiIDiscoveryEndpoint>
+        </SearchRequest>
+      </KnxNetIpMessage>
     </xml>
   </testcase>
 
   <testcase>
     <name>Search Response</name>
-    <raw>06100202004c0801c0a82a0b0e5736010200ffff000000082d409852e000170c000ab327553647697261204b4e582f49502d5363686e6974747374656c6c6500000000000802020103010401</raw>
+    <raw>
+      06100202004c0801c0a82a0b0e5736010200ffff000000082d409852e000170c000ab327553647697261204b4e582f49502d5363686e6974747374656c6c6500000000000802020103010401
+    </raw>
     <root-type>KnxNetIpMessage</root-type>
     <xml>
-      <SearchResponse className="org.apache.plc4x.java.knxnetip.readwrite.SearchResponse">
-        <hpaiControlEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIControlEndpoint">
-          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
-          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
-            <addr>wKgqCw==</addr>
-          </ipAddress>
-          <ipPort>3671</ipPort>
-        </hpaiControlEndpoint>
-        <dibDeviceInfo className="org.apache.plc4x.java.knxnetip.readwrite.DIBDeviceInfo">
-          <descriptionType>1</descriptionType>
-          <knxMedium>MEDIUM_TP1</knxMedium>
-          <deviceStatus className="org.apache.plc4x.java.knxnetip.readwrite.DeviceStatus">
-            <programMode>false</programMode>
-          </deviceStatus>
-          <knxAddress className="org.apache.plc4x.java.knxnetip.readwrite.KnxAddress">
-            <mainGroup>15</mainGroup>
-            <middleGroup>15</middleGroup>
-            <subGroup>255</subGroup>
-          </knxAddress>
-          <projectInstallationIdentifier className="org.apache.plc4x.java.knxnetip.readwrite.ProjectInstallationIdentifier">
-            <projectNumber>0</projectNumber>
-            <installationNumber>0</installationNumber>
-          </projectInstallationIdentifier>
-          <knxNetIpDeviceSerialNumber>AAgtQJhS</knxNetIpDeviceSerialNumber>
-          <knxNetIpDeviceMulticastAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
-            <addr>4AAXDA==</addr>
-          </knxNetIpDeviceMulticastAddress>
-          <knxNetIpDeviceMacAddress className="org.apache.plc4x.java.knxnetip.readwrite.MACAddress">
-            <addr>AAqzJ1U2</addr>
-          </knxNetIpDeviceMacAddress>
-          <deviceFriendlyName>R2lyYSBLTlgvSVAtU2Nobml0dHN0ZWxsZQAAAAAA</deviceFriendlyName>
-        </dibDeviceInfo>
-        <dibSuppSvcFamilies className="org.apache.plc4x.java.knxnetip.readwrite.DIBSuppSvcFamilies">
-          <descriptionType>2</descriptionType>
-          <serviceIds>
-            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpCore">
-              <version>1</version>
-            </serviceIds>
-            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpDeviceManagement">
-              <version>1</version>
-            </serviceIds>
-            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpTunneling">
-              <version>1</version>
-            </serviceIds>
-          </serviceIds>
-        </dibSuppSvcFamilies>
-      </SearchResponse>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">514</msgType>
+        <totalLength dataType="uint" bitLength="16">76</totalLength>
+        <SearchResponse>
+          <hpaiControlEndpoint>
+            <HPAIControlEndpoint>
+              <structureLength dataType="uint" bitLength="8">8</structureLength>
+              <hostProtocolCode>
+                <HostProtocolCode dataType="uint" bitLength="8" stringRepresentation="IPV4_UDP">1</HostProtocolCode>
+              </hostProtocolCode>
+              <ipAddress>
+                <IPAddress>
+                  <addr dataType="byte" bitLength="32">0xc0a82a0b</addr>
+                </IPAddress>
+              </ipAddress>
+              <ipPort dataType="uint" bitLength="16">3671</ipPort>
+            </HPAIControlEndpoint>
+          </hpaiControlEndpoint>
+          <dibDeviceInfo>
+            <DIBDeviceInfo>
+              <structureLength dataType="uint" bitLength="8">54</structureLength>
+              <descriptionType dataType="uint" bitLength="8">1</descriptionType>
+              <knxMedium>
+                <KnxMedium dataType="uint" bitLength="8" stringRepresentation="MEDIUM_TP1">2</KnxMedium>
+              </knxMedium>
+              <deviceStatus>
+                <DeviceStatus>
+                  <reserved dataType="uint" bitLength="7">0</reserved>
+                  <programMode dataType="bit" bitLength="1">false</programMode>
+                </DeviceStatus>
+              </deviceStatus>
+              <knxAddress>
+                <KnxAddress>
+                  <mainGroup dataType="uint" bitLength="4">15</mainGroup>
+                  <middleGroup dataType="uint" bitLength="4">15</middleGroup>
+                  <subGroup dataType="uint" bitLength="8">255</subGroup>
+                </KnxAddress>
+              </knxAddress>
+              <projectInstallationIdentifier>
+                <ProjectInstallationIdentifier>
+                  <projectNumber dataType="uint" bitLength="8">0</projectNumber>
+                  <installationNumber dataType="uint" bitLength="8">0</installationNumber>
+                </ProjectInstallationIdentifier>
+              </projectInstallationIdentifier>
+              <knxNetIpDeviceSerialNumber dataType="byte" bitLength="48">0x00082d409852</knxNetIpDeviceSerialNumber>
+              <knxNetIpDeviceMulticastAddress>
+                <IPAddress>
+                  <addr dataType="byte" bitLength="32">0xe000170c</addr>
+                </IPAddress>
+              </knxNetIpDeviceMulticastAddress>
+              <knxNetIpDeviceMacAddress>
+                <MACAddress>
+                  <addr dataType="byte" bitLength="48">0x000ab3275536</addr>
+                </MACAddress>
+              </knxNetIpDeviceMacAddress>
+              <deviceFriendlyName dataType="byte" bitLength="240">0x47697261204b4e582f49502d5363686e6974747374656c6c650000000000</deviceFriendlyName>
+            </DIBDeviceInfo>
+          </dibDeviceInfo>
+          <dibSuppSvcFamilies>
+            <DIBSuppSvcFamilies>
+              <structureLength dataType="uint" bitLength="8">8</structureLength>
+              <descriptionType dataType="uint" bitLength="8">2</descriptionType>
+              <serviceIds isList="true">
+                <ServiceId>
+                  <serviceType dataType="uint" bitLength="8">2</serviceType>
+                  <KnxNetIpCore>
+                    <version dataType="uint" bitLength="8">1</version>
+                  </KnxNetIpCore>
+                </ServiceId>
+                <ServiceId>
+                  <serviceType dataType="uint" bitLength="8">3</serviceType>
+                  <KnxNetIpDeviceManagement>
+                    <version dataType="uint" bitLength="8">1</version>
+                  </KnxNetIpDeviceManagement>
+                </ServiceId>
+                <ServiceId>
+                  <serviceType dataType="uint" bitLength="8">4</serviceType>
+                  <KnxNetIpTunneling>
+                    <version dataType="uint" bitLength="8">1</version>
+                  </KnxNetIpTunneling>
+                </ServiceId>
+              </serviceIds>
+            </DIBSuppSvcFamilies>
+          </dibSuppSvcFamilies>
+        </SearchResponse>
+      </KnxNetIpMessage>
     </xml>
   </testcase>
 
@@ -191,146 +251,270 @@
     <raw>06100203000e0801000000000000</raw>
     <root-type>KnxNetIpMessage</root-type>
     <xml>
-      <DescriptionRequest className="org.apache.plc4x.java.knxnetip.readwrite.DescriptionRequest">
-        <hpaiControlEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIControlEndpoint">
-          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
-          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
-            <addr>AAAAAA==</addr>
-          </ipAddress>
-          <ipPort>0</ipPort>
-        </hpaiControlEndpoint>
-      </DescriptionRequest>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">515</msgType>
+        <totalLength dataType="uint" bitLength="16">14</totalLength>
+        <DescriptionRequest>
+          <hpaiControlEndpoint>
+            <HPAIControlEndpoint>
+              <structureLength dataType="uint" bitLength="8">8</structureLength>
+              <hostProtocolCode>
+                <HostProtocolCode dataType="uint" bitLength="8" stringRepresentation="IPV4_UDP">1</HostProtocolCode>
+              </hostProtocolCode>
+              <ipAddress>
+                <IPAddress>
+                  <addr dataType="byte" bitLength="32">0x00000000</addr>
+                </IPAddress>
+              </ipAddress>
+              <ipPort dataType="uint" bitLength="16">0</ipPort>
+            </HPAIControlEndpoint>
+          </hpaiControlEndpoint>
+        </DescriptionRequest>
+      </KnxNetIpMessage>
     </xml>
   </testcase>
 
   <testcase>
     <name>Description Response</name>
-    <raw>06100204004436010200ffff000000082d409852e000170c000ab327553647697261204b4e582f49502d5363686e6974747374656c6c6500000000000802020103010401</raw>
+    <raw>
+      06100204004436010200ffff000000082d409852e000170c000ab327553647697261204b4e582f49502d5363686e6974747374656c6c6500000000000802020103010401
+    </raw>
     <root-type>KnxNetIpMessage</root-type>
     <xml>
-      <DescriptionResponse className="org.apache.plc4x.java.knxnetip.readwrite.DescriptionResponse">
-        <dibDeviceInfo className="org.apache.plc4x.java.knxnetip.readwrite.DIBDeviceInfo">
-          <descriptionType>1</descriptionType>
-          <knxMedium>MEDIUM_TP1</knxMedium>
-          <deviceStatus className="org.apache.plc4x.java.knxnetip.readwrite.DeviceStatus">
-            <programMode>false</programMode>
-          </deviceStatus>
-          <knxAddress className="org.apache.plc4x.java.knxnetip.readwrite.KnxAddress">
-            <mainGroup>15</mainGroup>
-            <middleGroup>15</middleGroup>
-            <subGroup>255</subGroup>
-          </knxAddress>
-          <projectInstallationIdentifier className="org.apache.plc4x.java.knxnetip.readwrite.ProjectInstallationIdentifier">
-            <projectNumber>0</projectNumber>
-            <installationNumber>0</installationNumber>
-          </projectInstallationIdentifier>
-          <knxNetIpDeviceSerialNumber>AAgtQJhS</knxNetIpDeviceSerialNumber>
-          <knxNetIpDeviceMulticastAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
-            <addr>4AAXDA==</addr>
-          </knxNetIpDeviceMulticastAddress>
-          <knxNetIpDeviceMacAddress className="org.apache.plc4x.java.knxnetip.readwrite.MACAddress">
-            <addr>AAqzJ1U2</addr>
-          </knxNetIpDeviceMacAddress>
-          <deviceFriendlyName>R2lyYSBLTlgvSVAtU2Nobml0dHN0ZWxsZQAAAAAA</deviceFriendlyName>
-        </dibDeviceInfo>
-        <dibSuppSvcFamilies className="org.apache.plc4x.java.knxnetip.readwrite.DIBSuppSvcFamilies">
-          <descriptionType>2</descriptionType>
-          <serviceIds>
-            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpCore">
-              <version>1</version>
-            </serviceIds>
-            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpDeviceManagement">
-              <version>1</version>
-            </serviceIds>
-            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpTunneling">
-              <version>1</version>
-            </serviceIds>
-          </serviceIds>
-        </dibSuppSvcFamilies>
-      </DescriptionResponse>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">516</msgType>
+        <totalLength dataType="uint" bitLength="16">68</totalLength>
+        <DescriptionResponse>
+          <dibDeviceInfo>
+            <DIBDeviceInfo>
+              <structureLength dataType="uint" bitLength="8">54</structureLength>
+              <descriptionType dataType="uint" bitLength="8">1</descriptionType>
+              <knxMedium>
+                <KnxMedium dataType="uint" bitLength="8" stringRepresentation="MEDIUM_TP1">2</KnxMedium>
+              </knxMedium>
+              <deviceStatus>
+                <DeviceStatus>
+                  <reserved dataType="uint" bitLength="7">0</reserved>
+                  <programMode dataType="bit" bitLength="1">false</programMode>
+                </DeviceStatus>
+              </deviceStatus>
+              <knxAddress>
+                <KnxAddress>
+                  <mainGroup dataType="uint" bitLength="4">15</mainGroup>
+                  <middleGroup dataType="uint" bitLength="4">15</middleGroup>
+                  <subGroup dataType="uint" bitLength="8">255</subGroup>
+                </KnxAddress>
+              </knxAddress>
+              <projectInstallationIdentifier>
+                <ProjectInstallationIdentifier>
+                  <projectNumber dataType="uint" bitLength="8">0</projectNumber>
+                  <installationNumber dataType="uint" bitLength="8">0</installationNumber>
+                </ProjectInstallationIdentifier>
+              </projectInstallationIdentifier>
+              <knxNetIpDeviceSerialNumber dataType="byte" bitLength="48">0x00082d409852</knxNetIpDeviceSerialNumber>
+              <knxNetIpDeviceMulticastAddress>
+                <IPAddress>
+                  <addr dataType="byte" bitLength="32">0xe000170c</addr>
+                </IPAddress>
+              </knxNetIpDeviceMulticastAddress>
+              <knxNetIpDeviceMacAddress>
+                <MACAddress>
+                  <addr dataType="byte" bitLength="48">0x000ab3275536</addr>
+                </MACAddress>
+              </knxNetIpDeviceMacAddress>
+              <deviceFriendlyName dataType="byte" bitLength="240">0x47697261204b4e582f49502d5363686e6974747374656c6c650000000000</deviceFriendlyName>
+            </DIBDeviceInfo>
+          </dibDeviceInfo>
+          <dibSuppSvcFamilies>
+            <DIBSuppSvcFamilies>
+              <structureLength dataType="uint" bitLength="8">8</structureLength>
+              <descriptionType dataType="uint" bitLength="8">2</descriptionType>
+              <serviceIds isList="true">
+                <ServiceId>
+                  <serviceType dataType="uint" bitLength="8">2</serviceType>
+                  <KnxNetIpCore>
+                    <version dataType="uint" bitLength="8">1</version>
+                  </KnxNetIpCore>
+                </ServiceId>
+                <ServiceId>
+                  <serviceType dataType="uint" bitLength="8">3</serviceType>
+                  <KnxNetIpDeviceManagement>
+                    <version dataType="uint" bitLength="8">1</version>
+                  </KnxNetIpDeviceManagement>
+                </ServiceId>
+                <ServiceId>
+                  <serviceType dataType="uint" bitLength="8">4</serviceType>
+                  <KnxNetIpTunneling>
+                    <version dataType="uint" bitLength="8">1</version>
+                  </KnxNetIpTunneling>
+                </ServiceId>
+              </serviceIds>
+            </DIBSuppSvcFamilies>
+          </dibSuppSvcFamilies>
+        </DescriptionResponse>
+      </KnxNetIpMessage>
     </xml>
   </testcase>
 
   <testcase>
     <name>Connect Request</name>
-    <raw>06100205001a0801c0a82a46f4310801c0a82a46f43204040200</raw>
+    <!--raw>06100205001a0801c0a82a46f4310801c0a82a46f43204040200</raw-->
+    <raw>06100205001a0801c0a82ac8d6b40801c0a82ac8d6b404040200</raw>
     <root-type>KnxNetIpMessage</root-type>
     <xml>
-      <ConnectionRequest className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequest">
-        <hpaiDiscoveryEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIDiscoveryEndpoint">
-          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
-          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
-            <addr>wKgqRg==</addr>
-          </ipAddress>
-          <ipPort>62513</ipPort>
-        </hpaiDiscoveryEndpoint>
-        <hpaiDataEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIDataEndpoint">
-          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
-          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
-            <addr>wKgqRg==</addr>
-          </ipAddress>
-          <ipPort>62514</ipPort>
-        </hpaiDataEndpoint>
-        <connectionRequestInformation className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequestInformationTunnelConnection">
-          <knxLayer>TUNNEL_LINK_LAYER</knxLayer>
-        </connectionRequestInformation>
-      </ConnectionRequest>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">517</msgType>
+        <totalLength dataType="uint" bitLength="16">26</totalLength>
+        <ConnectionRequest>
+          <hpaiDiscoveryEndpoint>
+            <HPAIDiscoveryEndpoint>
+              <structureLength dataType="uint" bitLength="8">8</structureLength>
+              <hostProtocolCode>
+                <HostProtocolCode dataType="uint" bitLength="8" stringRepresentation="IPV4_UDP">1</HostProtocolCode>
+              </hostProtocolCode>
+              <ipAddress>
+                <IPAddress>
+                  <addr dataType="byte" bitLength="32">0xc0a82ac8</addr>
+                </IPAddress>
+              </ipAddress>
+              <ipPort dataType="uint" bitLength="16">54964</ipPort>
+            </HPAIDiscoveryEndpoint>
+          </hpaiDiscoveryEndpoint>
+          <hpaiDataEndpoint>
+            <HPAIDataEndpoint>
+              <structureLength dataType="uint" bitLength="8">8</structureLength>
+              <hostProtocolCode>
+                <HostProtocolCode dataType="uint" bitLength="8" stringRepresentation="IPV4_UDP">1</HostProtocolCode>
+              </hostProtocolCode>
+              <ipAddress>
+                <IPAddress>
+                  <addr dataType="byte" bitLength="32">0xc0a82ac8</addr>
+                </IPAddress>
+              </ipAddress>
+              <ipPort dataType="uint" bitLength="16">54964</ipPort>
+            </HPAIDataEndpoint>
+          </hpaiDataEndpoint>
+          <connectionRequestInformation>
+            <ConnectionRequestInformation>
+              <structureLength dataType="uint" bitLength="8">4</structureLength>
+              <connectionType dataType="uint" bitLength="8">4</connectionType>
+              <ConnectionRequestInformationTunnelConnection>
+                <knxLayer>
+                  <KnxLayer dataType="uint" bitLength="8" stringRepresentation="TUNNEL_LINK_LAYER">2</KnxLayer>
+                </knxLayer>
+                <reserved dataType="uint" bitLength="8">0</reserved>
+              </ConnectionRequestInformationTunnelConnection>
+            </ConnectionRequestInformation>
+          </connectionRequestInformation>
+        </ConnectionRequest>
+      </KnxNetIpMessage>
     </xml>
   </testcase>
 
   <testcase>
     <name>Connect Response</name>
-    <raw>06100206001466000801c0a82a0b0e5704041101</raw>
+    <raw>06100206001402000801c0a82a0b0e570404fffe</raw>
     <root-type>KnxNetIpMessage</root-type>
     <xml>
-      <ConnectionResponse className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionResponse">
-        <communicationChannelId>102</communicationChannelId>
-        <status>NO_ERROR</status>
-        <hpaiDataEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIDataEndpoint">
-          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
-          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
-            <addr>wKgqCw==</addr>
-          </ipAddress>
-          <ipPort>3671</ipPort>
-        </hpaiDataEndpoint>
-        <connectionResponseDataBlock className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionResponseDataBlockTunnelConnection">
-          <knxAddress className="org.apache.plc4x.java.knxnetip.readwrite.KnxAddress">
-            <mainGroup>1</mainGroup>
-            <middleGroup>1</middleGroup>
-            <subGroup>1</subGroup>
-          </knxAddress>
-        </connectionResponseDataBlock>
-      </ConnectionResponse>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">518</msgType>
+        <totalLength dataType="uint" bitLength="16">20</totalLength>
+        <ConnectionResponse>
+          <communicationChannelId dataType="uint" bitLength="8">2</communicationChannelId>
+          <status>
+            <Status dataType="uint" bitLength="8" stringRepresentation="NO_ERROR">0</Status>
+          </status>
+          <hpaiDataEndpoint>
+            <HPAIDataEndpoint>
+              <structureLength dataType="uint" bitLength="8">8</structureLength>
+              <hostProtocolCode>
+                <HostProtocolCode dataType="uint" bitLength="8" stringRepresentation="IPV4_UDP">1</HostProtocolCode>
+              </hostProtocolCode>
+              <ipAddress>
+                <IPAddress>
+                  <addr dataType="byte" bitLength="32">0xc0a82a0b</addr>
+                </IPAddress>
+              </ipAddress>
+              <ipPort dataType="uint" bitLength="16">3671</ipPort>
+            </HPAIDataEndpoint>
+          </hpaiDataEndpoint>
+          <connectionResponseDataBlock>
+            <ConnectionResponseDataBlock>
+              <structureLength dataType="uint" bitLength="8">4</structureLength>
+              <connectionType dataType="uint" bitLength="8">4</connectionType>
+              <ConnectionResponseDataBlockTunnelConnection>
+                <knxAddress>
+                  <KnxAddress>
+                    <mainGroup dataType="uint" bitLength="4">15</mainGroup>
+                    <middleGroup dataType="uint" bitLength="4">15</middleGroup>
+                    <subGroup dataType="uint" bitLength="8">254</subGroup>
+                  </KnxAddress>
+                </knxAddress>
+              </ConnectionResponseDataBlockTunnelConnection>
+            </ConnectionResponseDataBlock>
+          </connectionResponseDataBlock>
+        </ConnectionResponse>
+      </KnxNetIpMessage>
     </xml>
   </testcase>
 
   <testcase>
     <name>Connection State Request</name>
-    <raw>06100207001066000801c0a82a46f431</raw>
+    <raw>06100207001002000801c0a82ac8d6b4</raw>
     <root-type>KnxNetIpMessage</root-type>
     <xml>
-      <ConnectionStateRequest className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionStateRequest">
-        <communicationChannelId>102</communicationChannelId>
-        <hpaiControlEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIControlEndpoint">
-          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
-          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
-            <addr>wKgqRg==</addr>
-          </ipAddress>
-          <ipPort>62513</ipPort>
-        </hpaiControlEndpoint>
-      </ConnectionStateRequest>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">519</msgType>
+        <totalLength dataType="uint" bitLength="16">16</totalLength>
+        <ConnectionStateRequest>
+          <communicationChannelId dataType="uint" bitLength="8">2</communicationChannelId>
+          <reserved dataType="uint" bitLength="8">0</reserved>
+          <hpaiControlEndpoint>
+            <HPAIControlEndpoint>
+              <structureLength dataType="uint" bitLength="8">8</structureLength>
+              <hostProtocolCode>
+                <HostProtocolCode dataType="uint" bitLength="8" stringRepresentation="IPV4_UDP">1</HostProtocolCode>
+              </hostProtocolCode>
+              <ipAddress>
+                <IPAddress>
+                  <addr dataType="byte" bitLength="32">0xc0a82ac8</addr>
+                </IPAddress>
+              </ipAddress>
+              <ipPort dataType="uint" bitLength="16">54964</ipPort>
+            </HPAIControlEndpoint>
+          </hpaiControlEndpoint>
+        </ConnectionStateRequest>
+      </KnxNetIpMessage>
     </xml>
   </testcase>
 
   <testcase>
     <name>Connection State Response</name>
-    <raw>0610020800086600</raw>
+    <raw>0610020800080200</raw>
     <root-type>KnxNetIpMessage</root-type>
     <xml>
-      <ConnectionStateResponse className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionStateResponse">
-        <communicationChannelId>102</communicationChannelId>
-        <status>NO_ERROR</status>
-      </ConnectionStateResponse>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">520</msgType>
+        <totalLength dataType="uint" bitLength="16">8</totalLength>
+        <ConnectionStateResponse>
+          <communicationChannelId dataType="uint" bitLength="8">2</communicationChannelId>
+          <status>
+            <Status dataType="uint" bitLength="8" stringRepresentation="NO_ERROR">0</Status>
+          </status>
+        </ConnectionStateResponse>
+      </KnxNetIpMessage>
     </xml>
   </testcase>
 
@@ -339,19 +523,34 @@
     <raw>06100310001104670000fc000001531001</raw>
     <root-type>KnxNetIpMessage</root-type>
     <xml>
-      <DeviceConfigurationRequest className="org.apache.plc4x.java.knxnetip.readwrite.DeviceConfigurationRequest">
-        <deviceConfigurationRequestDataBlock className="org.apache.plc4x.java.knxnetip.readwrite.DeviceConfigurationRequestDataBlock">
-          <communicationChannelId>103</communicationChannelId>
-          <sequenceCounter>0</sequenceCounter>
-        </deviceConfigurationRequestDataBlock>
-        <cemi className="org.apache.plc4x.java.knxnetip.readwrite.CEMIMPropReadReq">
-          <interfaceObjectType>0</interfaceObjectType>
-          <objectInstance>1</objectInstance>
-          <propertyId>83</propertyId>
-          <numberOfElements>1</numberOfElements>
-          <startIndex>1</startIndex>
-        </cemi>
-      </DeviceConfigurationRequest>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">784</msgType>
+        <totalLength dataType="uint" bitLength="16">17</totalLength>
+        <DeviceConfigurationRequest>
+          <deviceConfigurationRequestDataBlock>
+            <DeviceConfigurationRequestDataBlock>
+              <structureLength dataType="uint" bitLength="8">4</structureLength>
+              <communicationChannelId dataType="uint" bitLength="8">103</communicationChannelId>
+              <sequenceCounter dataType="uint" bitLength="8">0</sequenceCounter>
+              <reserved dataType="uint" bitLength="8">0</reserved>
+            </DeviceConfigurationRequestDataBlock>
+          </deviceConfigurationRequestDataBlock>
+          <cemi>
+            <CEMI>
+              <messageCode dataType="uint" bitLength="8">252</messageCode>
+              <MPropReadReq>
+                <interfaceObjectType dataType="uint" bitLength="16">0</interfaceObjectType>
+                <objectInstance dataType="uint" bitLength="8">1</objectInstance>
+                <propertyId dataType="uint" bitLength="8">83</propertyId>
+                <numberOfElements dataType="uint" bitLength="4">1</numberOfElements>
+                <startIndex dataType="uint" bitLength="12">1</startIndex>
+              </MPropReadReq>
+            </CEMI>
+          </cemi>
+        </DeviceConfigurationRequest>
+      </KnxNetIpMessage>
     </xml>
   </testcase>
 
@@ -360,31 +559,56 @@
     <raw>06100311000a04670000</raw>
     <root-type>KnxNetIpMessage</root-type>
     <xml>
-      <DeviceConfigurationAck className="org.apache.plc4x.java.knxnetip.readwrite.DeviceConfigurationAck">
-        <deviceConfigurationAckDataBlock className="org.apache.plc4x.java.knxnetip.readwrite.DeviceConfigurationAckDataBlock">
-          <communicationChannelId>103</communicationChannelId>
-          <sequenceCounter>0</sequenceCounter>
-          <status>NO_ERROR</status>
-        </deviceConfigurationAckDataBlock>
-      </DeviceConfigurationAck>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">785</msgType>
+        <totalLength dataType="uint" bitLength="16">10</totalLength>
+        <DeviceConfigurationAck>
+          <deviceConfigurationAckDataBlock>
+            <DeviceConfigurationAckDataBlock>
+              <structureLength dataType="uint" bitLength="8">4</structureLength>
+              <communicationChannelId dataType="uint" bitLength="8">103</communicationChannelId>
+              <sequenceCounter dataType="uint" bitLength="8">0</sequenceCounter>
+              <status>
+                <Status dataType="uint" bitLength="8" stringRepresentation="NO_ERROR">0</Status>
+              </status>
+            </DeviceConfigurationAckDataBlock>
+          </deviceConfigurationAckDataBlock>
+        </DeviceConfigurationAck>
+      </KnxNetIpMessage>
     </xml>
   </testcase>
 
   <testcase>
     <name>Disconnect Request</name>
-    <raw>06100209001067000801c0a82a46f431</raw>
+    <raw>06100209001001000801c0a82a0b0e57</raw>
     <root-type>KnxNetIpMessage</root-type>
     <xml>
-      <DisconnectRequest className="org.apache.plc4x.java.knxnetip.readwrite.DisconnectRequest">
-        <communicationChannelId>103</communicationChannelId>
-        <hpaiControlEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIControlEndpoint">
-          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
-          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
-            <addr>wKgqRg==</addr>
-          </ipAddress>
-          <ipPort>62513</ipPort>
-        </hpaiControlEndpoint>
-      </DisconnectRequest>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">521</msgType>
+        <totalLength dataType="uint" bitLength="16">16</totalLength>
+        <DisconnectRequest>
+          <communicationChannelId dataType="uint" bitLength="8">1</communicationChannelId>
+          <reserved dataType="uint" bitLength="8">0</reserved>
+          <hpaiControlEndpoint>
+            <HPAIControlEndpoint>
+              <structureLength dataType="uint" bitLength="8">8</structureLength>
+              <hostProtocolCode>
+                <HostProtocolCode dataType="uint" bitLength="8" stringRepresentation="IPV4_UDP">1</HostProtocolCode>
+              </hostProtocolCode>
+              <ipAddress>
+                <IPAddress>
+                  <addr dataType="byte" bitLength="32">0xc0a82a0b</addr>
+                </IPAddress>
+              </ipAddress>
+              <ipPort dataType="uint" bitLength="16">3671</ipPort>
+            </HPAIControlEndpoint>
+          </hpaiControlEndpoint>
+        </DisconnectRequest>
+      </KnxNetIpMessage>
     </xml>
   </testcase>
 
@@ -393,15 +617,102 @@
     <raw>0610020a00086600</raw>
     <root-type>KnxNetIpMessage</root-type>
     <xml>
-      <DisconnectResponse className="org.apache.plc4x.java.knxnetip.readwrite.DisconnectResponse">
-        <communicationChannelId>102</communicationChannelId>
-        <status>NO_ERROR</status>
-      </DisconnectResponse>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">522</msgType>
+        <totalLength dataType="uint" bitLength="16">8</totalLength>
+        <DisconnectResponse>
+          <communicationChannelId dataType="uint" bitLength="8">102</communicationChannelId>
+          <status>
+            <Status dataType="uint" bitLength="8" stringRepresentation="NO_ERROR">0</Status>
+          </status>
+        </DisconnectResponse>
+      </KnxNetIpMessage>
     </xml>
   </testcase>
 
   <testcase>
     <name>Tunneling Request</name>
+    <raw>061004200015040200002900bce0220a120c010081</raw>
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">1056</msgType>
+        <totalLength dataType="uint" bitLength="16">21</totalLength>
+        <TunnelingRequest>
+          <tunnelingRequestDataBlock>
+            <TunnelingRequestDataBlock>
+              <structureLength dataType="uint" bitLength="8">4</structureLength>
+              <communicationChannelId dataType="uint" bitLength="8">2</communicationChannelId>
+              <sequenceCounter dataType="uint" bitLength="8">0</sequenceCounter>
+              <reserved dataType="uint" bitLength="8">0</reserved>
+            </TunnelingRequestDataBlock>
+          </tunnelingRequestDataBlock>
+          <cemi>
+            <CEMI>
+              <messageCode dataType="uint" bitLength="8">41</messageCode>
+              <LDataInd>
+                <additionalInformationLength dataType="uint" bitLength="8">0</additionalInformationLength>
+                <additionalInformation isList="true">
+                </additionalInformation>
+                <dataFrame>
+                  <LDataFrame>
+                    <frameType dataType="bit" bitLength="1">true</frameType>
+                    <polling dataType="bit" bitLength="1">false</polling>
+                    <notRepeated dataType="bit" bitLength="1">true</notRepeated>
+                    <notAckFrame dataType="bit" bitLength="1">true</notAckFrame>
+                    <priority>
+                      <CEMIPriority dataType="uint" bitLength="2" stringRepresentation="LOW">3</CEMIPriority>
+                    </priority>
+                    <acknowledgeRequested dataType="bit" bitLength="1">false</acknowledgeRequested>
+                    <errorFlag dataType="bit" bitLength="1">false</errorFlag>
+                    <LDataExtended>
+                      <groupAddress dataType="bit" bitLength="1">true</groupAddress>
+                      <hopCount dataType="uint" bitLength="3">6</hopCount>
+                      <extendedFrameFormat dataType="uint" bitLength="4">0</extendedFrameFormat>
+                      <sourceAddress>
+                        <KnxAddress>
+                          <mainGroup dataType="uint" bitLength="4">2</mainGroup>
+                          <middleGroup dataType="uint" bitLength="4">2</middleGroup>
+                          <subGroup dataType="uint" bitLength="8">10</subGroup>
+                        </KnxAddress>
+                      </sourceAddress>
+                      <destinationAddress dataType="byte" bitLength="16">0x120c</destinationAddress>
+                      <dataLength dataType="uint" bitLength="8">1</dataLength>
+                      <apdu>
+                        <Apdu>
+                          <control dataType="uint" bitLength="1">0</control>
+                          <numbered dataType="bit" bitLength="1">false</numbered>
+                          <counter dataType="uint" bitLength="4">0</counter>
+                          <ApduDataContainer>
+                            <dataApdu>
+                              <ApduData>
+                                <apciType dataType="uint" bitLength="4">2</apciType>
+                                <ApduDataGroupValueWrite>
+                                  <dataFirstByte dataType="int" bitLength="6">1</dataFirstByte>
+                                  <data dataType="byte" bitLength="0">0x</data>
+                                </ApduDataGroupValueWrite>
+                              </ApduData>
+                            </dataApdu>
+                          </ApduDataContainer>
+                        </Apdu>
+                      </apdu>
+                    </LDataExtended>
+                  </LDataFrame>
+                </dataFrame>
+              </LDataInd>
+            </CEMI>
+          </cemi>
+        </TunnelingRequest>
+      </KnxNetIpMessage>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Tunneling Request (Busmon)</name>
     <raw>06100420001c046b00002b0703010504024502bc360a1e0ce100810d</raw>
     <!--
     Raw CEMI Frame: bc360a1e0ce100810d
@@ -409,51 +720,99 @@
     -->
     <root-type>KnxNetIpMessage</root-type>
     <xml>
-      <TunnelingRequest className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingRequest">
-        <tunnelingRequestDataBlock className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingRequestDataBlock">
-          <communicationChannelId>107</communicationChannelId>
-          <sequenceCounter>0</sequenceCounter>
-        </tunnelingRequestDataBlock>
-        <cemi className="org.apache.plc4x.java.knxnetip.readwrite.CEMIBusmonInd">
-          <additionalInformationLength>7</additionalInformationLength>
-          <additionalInformation>
-            <additionalInformation className="org.apache.plc4x.java.knxnetip.readwrite.CEMIAdditionalInformationBusmonitorInfo">
-              <frameErrorFlag>false</frameErrorFlag>
-              <bitErrorFlag>false</bitErrorFlag>
-              <parityErrorFlag>false</parityErrorFlag>
-              <unknownFlag>false</unknownFlag>
-              <lostFlag>false</lostFlag>
-              <sequenceNumber>5</sequenceNumber>
-            </additionalInformation>
-            <additionalInformation className="org.apache.plc4x.java.knxnetip.readwrite.CEMIAdditionalInformationRelativeTimestamp">
-              <relativeTimestamp className="org.apache.plc4x.java.knxnetip.readwrite.RelativeTimestamp">
-                <timestamp>17666</timestamp>
-              </relativeTimestamp>
-            </additionalInformation>
-          </additionalInformation>
-          <cemiFrame className="org.apache.plc4x.java.knxnetip.readwrite.CEMIFrameData">
-            <repeated>true</repeated>
-            <priority>LOW</priority>
-            <acknowledgeRequested>false</acknowledgeRequested>
-            <errorFlag>false</errorFlag>
-            <sourceAddress className="org.apache.plc4x.java.knxnetip.readwrite.KnxAddress">
-              <mainGroup>3</mainGroup>
-              <middleGroup>6</middleGroup>
-              <subGroup>10</subGroup>
-            </sourceAddress>
-            <destinationAddress>Hgw=</destinationAddress>
-            <groupAddress>true</groupAddress>
-            <hopCount>6</hopCount>
-            <dataLength>1</dataLength>
-            <tcpi>UNNUMBERED_DATA_PACKET</tcpi>
-            <counter>0</counter>
-            <apci>GROUP_VALUE_WRITE_PDU</apci>
-            <dataFirstByte>1</dataFirstByte>
-            <data></data>
-            <crc>13</crc>
-          </cemiFrame>
-        </cemi>
-      </TunnelingRequest>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">1056</msgType>
+        <totalLength dataType="uint" bitLength="16">28</totalLength>
+        <TunnelingRequest>
+          <tunnelingRequestDataBlock>
+            <TunnelingRequestDataBlock>
+              <structureLength dataType="uint" bitLength="8">4</structureLength>
+              <communicationChannelId dataType="uint" bitLength="8">107</communicationChannelId>
+              <sequenceCounter dataType="uint" bitLength="8">0</sequenceCounter>
+              <reserved dataType="uint" bitLength="8">0</reserved>
+            </TunnelingRequestDataBlock>
+          </tunnelingRequestDataBlock>
+          <cemi>
+            <CEMI>
+              <messageCode dataType="uint" bitLength="8">43</messageCode>
+              <LBusmonInd>
+                <additionalInformationLength dataType="uint" bitLength="8">7</additionalInformationLength>
+                <additionalInformation isList="true">
+                  <CEMIAdditionalInformation>
+                    <additionalInformationType dataType="uint" bitLength="8">3</additionalInformationType>
+                    <CEMIAdditionalInformationBusmonitorInfo>
+                      <len dataType="uint" bitLength="8">1</len>
+                      <frameErrorFlag dataType="bit" bitLength="1">false</frameErrorFlag>
+                      <bitErrorFlag dataType="bit" bitLength="1">false</bitErrorFlag>
+                      <parityErrorFlag dataType="bit" bitLength="1">false</parityErrorFlag>
+                      <unknownFlag dataType="bit" bitLength="1">false</unknownFlag>
+                      <lostFlag dataType="bit" bitLength="1">false</lostFlag>
+                      <sequenceNumber dataType="uint" bitLength="3">5</sequenceNumber>
+                    </CEMIAdditionalInformationBusmonitorInfo>
+                  </CEMIAdditionalInformation>
+                  <CEMIAdditionalInformation>
+                    <additionalInformationType dataType="uint" bitLength="8">4</additionalInformationType>
+                    <CEMIAdditionalInformationRelativeTimestamp>
+                      <len dataType="uint" bitLength="8">2</len>
+                      <relativeTimestamp>
+                        <RelativeTimestamp>
+                          <timestamp dataType="uint" bitLength="16">17666</timestamp>
+                        </RelativeTimestamp>
+                      </relativeTimestamp>
+                    </CEMIAdditionalInformationRelativeTimestamp>
+                  </CEMIAdditionalInformation>
+                </additionalInformation>
+                <dataFrame>
+                  <LDataFrame>
+                    <frameType dataType="bit" bitLength="1">true</frameType>
+                    <polling dataType="bit" bitLength="1">false</polling>
+                    <notRepeated dataType="bit" bitLength="1">true</notRepeated>
+                    <notAckFrame dataType="bit" bitLength="1">true</notAckFrame>
+                    <priority>
+                      <CEMIPriority dataType="uint" bitLength="2" stringRepresentation="LOW">3</CEMIPriority>
+                    </priority>
+                    <acknowledgeRequested dataType="bit" bitLength="1">false</acknowledgeRequested>
+                    <errorFlag dataType="bit" bitLength="1">false</errorFlag>
+                    <LDataExtended>
+                      <groupAddress dataType="bit" bitLength="1">false</groupAddress>
+                      <hopCount dataType="uint" bitLength="3">3</hopCount>
+                      <extendedFrameFormat dataType="uint" bitLength="4">6</extendedFrameFormat>
+                      <sourceAddress>
+                        <KnxAddress>
+                          <mainGroup dataType="uint" bitLength="4">0</mainGroup>
+                          <middleGroup dataType="uint" bitLength="4">10</middleGroup>
+                          <subGroup dataType="uint" bitLength="8">30</subGroup>
+                        </KnxAddress>
+                      </sourceAddress>
+                      <destinationAddress dataType="byte" bitLength="16">0x0ce1</destinationAddress>
+                      <dataLength dataType="uint" bitLength="8">0</dataLength>
+                      <apdu>
+                        <Apdu>
+                          <control dataType="uint" bitLength="1">1</control>
+                          <numbered dataType="bit" bitLength="1">false</numbered>
+                          <counter dataType="uint" bitLength="4">0</counter>
+                          <ApduControlContainer>
+                            <controlApdu>
+                              <ApduControl>
+                                <controlType dataType="uint" bitLength="2">1</controlType>
+                                <ApduControlDisconnect>
+                                </ApduControlDisconnect>
+                              </ApduControl>
+                            </controlApdu>
+                          </ApduControlContainer>
+                        </Apdu>
+                      </apdu>
+                    </LDataExtended>
+                  </LDataFrame>
+                </dataFrame>
+                <crc dataType="uint" bitLength="8">13</crc>
+              </LBusmonInd>
+            </CEMI>
+          </cemi>
+        </TunnelingRequest>
+      </KnxNetIpMessage>
     </xml>
   </testcase>
 
@@ -462,13 +821,24 @@
     <raw>06100421000a046b0000</raw>
     <root-type>KnxNetIpMessage</root-type>
     <xml>
-      <TunnelingResponse className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingResponse">
-        <tunnelingResponseDataBlock className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingResponseDataBlock">
-          <communicationChannelId>107</communicationChannelId>
-          <sequenceCounter>0</sequenceCounter>
-          <status>NO_ERROR</status>
-        </tunnelingResponseDataBlock>
-      </TunnelingResponse>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">1057</msgType>
+        <totalLength dataType="uint" bitLength="16">10</totalLength>
+        <TunnelingResponse>
+          <tunnelingResponseDataBlock>
+            <TunnelingResponseDataBlock>
+              <structureLength dataType="uint" bitLength="8">4</structureLength>
+              <communicationChannelId dataType="uint" bitLength="8">107</communicationChannelId>
+              <sequenceCounter dataType="uint" bitLength="8">0</sequenceCounter>
+              <status>
+                <Status dataType="uint" bitLength="8" stringRepresentation="NO_ERROR">0</Status>
+              </status>
+            </TunnelingResponseDataBlock>
+          </tunnelingResponseDataBlock>
+        </TunnelingResponse>
+      </KnxNetIpMessage>
     </xml>
   </testcase>
 
@@ -477,24 +847,51 @@
     <raw>0610020500180801c0a82a46c4090801c0a82a46c40a0203</raw>
     <root-type>KnxNetIpMessage</root-type>
     <xml>
-      <ConnectionRequest className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequest">
-        <hpaiDiscoveryEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIDiscoveryEndpoint">
-          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
-          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
-            <addr>wKgqRg==</addr>
-          </ipAddress>
-          <ipPort>50185</ipPort>
-        </hpaiDiscoveryEndpoint>
-        <hpaiDataEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIDataEndpoint">
-          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
-          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
-            <addr>wKgqRg==</addr>
-          </ipAddress>
-          <ipPort>50186</ipPort>
-        </hpaiDataEndpoint>
-        <connectionRequestInformation className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequestInformationDeviceManagement"/>
-      </ConnectionRequest>
+      <KnxNetIpMessage>
+        <headerLength dataType="uint" bitLength="8">6</headerLength>
+        <protocolVersion dataType="uint" bitLength="8">16</protocolVersion>
+        <msgType dataType="uint" bitLength="16">517</msgType>
+        <totalLength dataType="uint" bitLength="16">24</totalLength>
+        <ConnectionRequest>
+          <hpaiDiscoveryEndpoint>
+            <HPAIDiscoveryEndpoint>
+              <structureLength dataType="uint" bitLength="8">8</structureLength>
+              <hostProtocolCode>
+                <HostProtocolCode dataType="uint" bitLength="8" stringRepresentation="IPV4_UDP">1</HostProtocolCode>
+              </hostProtocolCode>
+              <ipAddress>
+                <IPAddress>
+                  <addr dataType="byte" bitLength="32">0xc0a82a46</addr>
+                </IPAddress>
+              </ipAddress>
+              <ipPort dataType="uint" bitLength="16">50185</ipPort>
+            </HPAIDiscoveryEndpoint>
+          </hpaiDiscoveryEndpoint>
+          <hpaiDataEndpoint>
+            <HPAIDataEndpoint>
+              <structureLength dataType="uint" bitLength="8">8</structureLength>
+              <hostProtocolCode>
+                <HostProtocolCode dataType="uint" bitLength="8" stringRepresentation="IPV4_UDP">1</HostProtocolCode>
+              </hostProtocolCode>
+              <ipAddress>
+                <IPAddress>
+                  <addr dataType="byte" bitLength="32">0xc0a82a46</addr>
+                </IPAddress>
+              </ipAddress>
+              <ipPort dataType="uint" bitLength="16">50186</ipPort>
+            </HPAIDataEndpoint>
+          </hpaiDataEndpoint>
+          <connectionRequestInformation>
+            <ConnectionRequestInformation>
+              <structureLength dataType="uint" bitLength="8">2</structureLength>
+              <connectionType dataType="uint" bitLength="8">3</connectionType>
+              <ConnectionRequestInformationDeviceManagement>
+              </ConnectionRequestInformationDeviceManagement>
+            </ConnectionRequestInformation>
+          </connectionRequestInformation>
+        </ConnectionRequest>
+      </KnxNetIpMessage>
     </xml>
   </testcase>
 
-</test:testsuite>
\ No newline at end of file
+</test:testsuite>
diff --git a/sandbox/plc4net/drivers/knxnetip-test/test/knxnetip/readwrite/model/KnxDatapointTests.cs b/sandbox/plc4net/drivers/knxnetip-test/test/knxnetip/readwrite/model/KnxDatapointTests.cs
index 57e290d..6e0e5b6 100644
--- a/sandbox/plc4net/drivers/knxnetip-test/test/knxnetip/readwrite/model/KnxDatapointTests.cs
+++ b/sandbox/plc4net/drivers/knxnetip-test/test/knxnetip/readwrite/model/KnxDatapointTests.cs
@@ -35,7 +35,7 @@ namespace org.apache.plc4net.test.knxnetip.readwrite.model
             var input = StrToByteArray("0041b00000");
             IPlcValue expected = new PlcREAL(22.0f);
             
-            var actual = new KnxDatapoint().Parse(new ReadBuffer(input), formatName);
+            var actual = KnxDatapoint.StaticParse(new ReadBuffer(input), KnxDatapointType.DPT_SSSBMode);
             
             Assert.Equal(expected, actual);
         }
diff --git a/sandbox/plc4net/drivers/knxnetip/plc4net-driver-knxproj.csproj b/sandbox/plc4net/drivers/knxnetip/plc4net-driver-knxproj.csproj
index 27ae013..0be2cd7 100644
--- a/sandbox/plc4net/drivers/knxnetip/plc4net-driver-knxproj.csproj
+++ b/sandbox/plc4net/drivers/knxnetip/plc4net-driver-knxproj.csproj
@@ -36,4 +36,8 @@
     <ProjectReference Include="..\..\spi\plc4net-spi.csproj" />
   </ItemGroup>
 
+  <ItemGroup>
+    <PackageReference Include="NLog" Version="4.7.13" />
+  </ItemGroup>
+
 </Project>
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/AccessLevel.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/AccessLevel.cs
new file mode 100644
index 0000000..18a786c
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/AccessLevel.cs
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public enum AccessLevel
+    {
+        Level0 = 0x0,
+        Level1 = 0x1,
+        Level2 = 0x2,
+        Level3 = 0x3,
+        Level15 = 0xF,
+    }
+
+    public static class AccessLevelInfo
+    {
+
+        public static string Purpose(this AccessLevel value)
+        {
+            switch (value)
+            {
+                case AccessLevel.Level0: { /* '0x0' */
+                    return "system manufacturer";
+                }
+                case AccessLevel.Level1: { /* '0x1' */
+                    return "product manufacturer";
+                }
+                case AccessLevel.Level2: { /* '0x2' */
+                    return "configuration";
+                }
+                case AccessLevel.Level3: { /* '0x3' */
+                    return "end-user";
+                }
+                case AccessLevel.Level15: { /* '0xF' */
+                    return "read access";
+                }
+                default: {
+                    return null;
+                }
+            }
+        }
+
+        public static bool? NeedsAuthentication(this AccessLevel value)
+        {
+            switch (value)
+            {
+                case AccessLevel.Level0: { /* '0x0' */
+                    return true;
+                }
+                case AccessLevel.Level1: { /* '0x1' */
+                    return true;
+                }
+                case AccessLevel.Level2: { /* '0x2' */
+                    return true;
+                }
+                case AccessLevel.Level3: { /* '0x3' */
+                    return false;
+                }
+                case AccessLevel.Level15: { /* '0xF' */
+                    return false;
+                }
+                default: {
+                    return false;
+                }
+            }
+        }
+    }
+
+}
+
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/Apdu.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/Apdu.cs
new file mode 100644
index 0000000..595c0f6
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/Apdu.cs
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public abstract class Apdu
+    {
+
+        // Abstract accessors for discriminator values.
+        public abstract byte Control { get; }
+
+        // Properties.
+        public bool Numbered { get; }
+        public byte Counter { get; }
+
+        public Apdu(bool numbered, byte counter)
+        {
+            Numbered = numbered;
+            Counter = counter;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControl.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControl.cs
new file mode 100644
index 0000000..9c10240
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControl.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public abstract class ApduControl
+    {
+
+        // Abstract accessors for discriminator values.
+        public abstract byte ControlType { get; }
+
+        public ApduControl()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControlAck.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControlAck.cs
new file mode 100644
index 0000000..5561a37
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControlAck.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduControlAck : ApduControl
+    {
+
+        // Accessors for discriminator values.
+        public override byte ControlType => 0x2;
+
+        public ApduControlAck()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControlConnect.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControlConnect.cs
new file mode 100644
index 0000000..858a23a
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControlConnect.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduControlConnect : ApduControl
+    {
+
+        // Accessors for discriminator values.
+        public override byte ControlType => 0x0;
+
+        public ApduControlConnect()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControlContainer.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControlContainer.cs
new file mode 100644
index 0000000..a64c0fd
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControlContainer.cs
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduControlContainer : Apdu
+    {
+
+        // Accessors for discriminator values.
+        public override byte Control => 1;
+
+        // Properties.
+        public ApduControl ControlApdu { get; }
+
+        public ApduControlContainer(bool numbered, byte counter, ApduControl controlApdu)
+            : base(numbered, counter)
+        {
+            ControlApdu = controlApdu;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControlDisconnect.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControlDisconnect.cs
new file mode 100644
index 0000000..3a1843e
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControlDisconnect.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduControlDisconnect : ApduControl
+    {
+
+        // Accessors for discriminator values.
+        public override byte ControlType => 0x1;
+
+        public ApduControlDisconnect()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControlNack.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControlNack.cs
new file mode 100644
index 0000000..459c22d
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduControlNack.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduControlNack : ApduControl
+    {
+
+        // Accessors for discriminator values.
+        public override byte ControlType => 0x3;
+
+        public ApduControlNack()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduData.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduData.cs
new file mode 100644
index 0000000..b5b2aa1
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduData.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public abstract class ApduData
+    {
+
+        // Abstract accessors for discriminator values.
+        public abstract byte ApciType { get; }
+
+        public ApduData()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataAdcRead.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataAdcRead.cs
new file mode 100644
index 0000000..4e7cc24
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataAdcRead.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataAdcRead : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0x6;
+
+        public ApduDataAdcRead()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataAdcResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataAdcResponse.cs
new file mode 100644
index 0000000..37b4348
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataAdcResponse.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataAdcResponse : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0x7;
+
+        public ApduDataAdcResponse()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataContainer.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataContainer.cs
new file mode 100644
index 0000000..7969f31
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataContainer.cs
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataContainer : Apdu
+    {
+
+        // Accessors for discriminator values.
+        public override byte Control => 0;
+
+        // Properties.
+        public ApduData DataApdu { get; }
+
+        public ApduDataContainer(bool numbered, byte counter, ApduData dataApdu)
+            : base(numbered, counter)
+        {
+            DataApdu = dataApdu;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataDeviceDescriptorRead.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataDeviceDescriptorRead.cs
new file mode 100644
index 0000000..41921b5
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataDeviceDescriptorRead.cs
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataDeviceDescriptorRead : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0xC;
+
+        // Properties.
+        public byte DescriptorType { get; }
+
+        public ApduDataDeviceDescriptorRead(byte descriptorType)
+        {
+            DescriptorType = descriptorType;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataDeviceDescriptorResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataDeviceDescriptorResponse.cs
new file mode 100644
index 0000000..1259778
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataDeviceDescriptorResponse.cs
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataDeviceDescriptorResponse : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0xD;
+
+        // Properties.
+        public byte DescriptorType { get; }
+        public byte[] Data { get; }
+
+        public ApduDataDeviceDescriptorResponse(byte descriptorType, byte[] data)
+        {
+            DescriptorType = descriptorType;
+            Data = data;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExt.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExt.cs
new file mode 100644
index 0000000..90f7e4f
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExt.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public abstract class ApduDataExt
+    {
+
+        // Abstract accessors for discriminator values.
+        public abstract byte ExtApciType { get; }
+
+        public ApduDataExt()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtAuthorizeRequest.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtAuthorizeRequest.cs
new file mode 100644
index 0000000..c31800b
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtAuthorizeRequest.cs
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtAuthorizeRequest : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x11;
+
+        // Properties.
+        public byte Level { get; }
+        public byte[] Data { get; }
+
+        public ApduDataExtAuthorizeRequest(byte level, byte[] data)
+        {
+            Level = level;
+            Data = data;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtAuthorizeResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtAuthorizeResponse.cs
new file mode 100644
index 0000000..adab868
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtAuthorizeResponse.cs
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtAuthorizeResponse : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x12;
+
+        // Properties.
+        public byte Level { get; }
+
+        public ApduDataExtAuthorizeResponse(byte level)
+        {
+            Level = level;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressRead.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressRead.cs
new file mode 100644
index 0000000..c640fce
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressRead.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtDomainAddressRead : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x21;
+
+        public ApduDataExtDomainAddressRead()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressResponse.cs
new file mode 100644
index 0000000..87acf52
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressResponse.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtDomainAddressResponse : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x22;
+
+        public ApduDataExtDomainAddressResponse()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressSelectiveRead.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressSelectiveRead.cs
new file mode 100644
index 0000000..2c6034c
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressSelectiveRead.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtDomainAddressSelectiveRead : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x23;
+
+        public ApduDataExtDomainAddressSelectiveRead()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressSerialNumberRead.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressSerialNumberRead.cs
new file mode 100644
index 0000000..8099b85
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressSerialNumberRead.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtDomainAddressSerialNumberRead : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x2C;
+
+        public ApduDataExtDomainAddressSerialNumberRead()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressSerialNumberResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressSerialNumberResponse.cs
new file mode 100644
index 0000000..b0bf11f
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressSerialNumberResponse.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtDomainAddressSerialNumberResponse : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x2D;
+
+        public ApduDataExtDomainAddressSerialNumberResponse()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressSerialNumberWrite.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressSerialNumberWrite.cs
new file mode 100644
index 0000000..7cdd03b
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressSerialNumberWrite.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtDomainAddressSerialNumberWrite : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x2E;
+
+        public ApduDataExtDomainAddressSerialNumberWrite()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressWrite.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressWrite.cs
new file mode 100644
index 0000000..af01011
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtDomainAddressWrite.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtDomainAddressWrite : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x20;
+
+        public ApduDataExtDomainAddressWrite()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtFileStreamInfoReport.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtFileStreamInfoReport.cs
new file mode 100644
index 0000000..4e363fb
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtFileStreamInfoReport.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtFileStreamInfoReport : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x30;
+
+        public ApduDataExtFileStreamInfoReport()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtGroupPropertyValueInfoReport.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtGroupPropertyValueInfoReport.cs
new file mode 100644
index 0000000..943546e
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtGroupPropertyValueInfoReport.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtGroupPropertyValueInfoReport : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x2B;
+
+        public ApduDataExtGroupPropertyValueInfoReport()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtGroupPropertyValueRead.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtGroupPropertyValueRead.cs
new file mode 100644
index 0000000..4ea6cc8
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtGroupPropertyValueRead.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtGroupPropertyValueRead : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x28;
+
+        public ApduDataExtGroupPropertyValueRead()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtGroupPropertyValueResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtGroupPropertyValueResponse.cs
new file mode 100644
index 0000000..96e6591
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtGroupPropertyValueResponse.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtGroupPropertyValueResponse : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x29;
+
+        public ApduDataExtGroupPropertyValueResponse()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtGroupPropertyValueWrite.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtGroupPropertyValueWrite.cs
new file mode 100644
index 0000000..2d9df55
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtGroupPropertyValueWrite.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtGroupPropertyValueWrite : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x2A;
+
+        public ApduDataExtGroupPropertyValueWrite()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtIndividualAddressSerialNumberRead.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtIndividualAddressSerialNumberRead.cs
new file mode 100644
index 0000000..8ada652
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtIndividualAddressSerialNumberRead.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtIndividualAddressSerialNumberRead : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x1C;
+
+        public ApduDataExtIndividualAddressSerialNumberRead()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtIndividualAddressSerialNumberResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtIndividualAddressSerialNumberResponse.cs
new file mode 100644
index 0000000..8b21dea
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtIndividualAddressSerialNumberResponse.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtIndividualAddressSerialNumberResponse : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x1D;
+
+        public ApduDataExtIndividualAddressSerialNumberResponse()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtIndividualAddressSerialNumberWrite.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtIndividualAddressSerialNumberWrite.cs
new file mode 100644
index 0000000..d8e08c7
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtIndividualAddressSerialNumberWrite.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtIndividualAddressSerialNumberWrite : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x1E;
+
+        public ApduDataExtIndividualAddressSerialNumberWrite()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtKeyResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtKeyResponse.cs
new file mode 100644
index 0000000..05a02a3
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtKeyResponse.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtKeyResponse : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x14;
+
+        public ApduDataExtKeyResponse()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtKeyWrite.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtKeyWrite.cs
new file mode 100644
index 0000000..d950733
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtKeyWrite.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtKeyWrite : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x13;
+
+        public ApduDataExtKeyWrite()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtLinkRead.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtLinkRead.cs
new file mode 100644
index 0000000..187ea02
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtLinkRead.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtLinkRead : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x25;
+
+        public ApduDataExtLinkRead()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtLinkResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtLinkResponse.cs
new file mode 100644
index 0000000..af907e8
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtLinkResponse.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtLinkResponse : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x26;
+
+        public ApduDataExtLinkResponse()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtLinkWrite.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtLinkWrite.cs
new file mode 100644
index 0000000..e5a1000
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtLinkWrite.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtLinkWrite : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x27;
+
+        public ApduDataExtLinkWrite()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtMemoryBitWrite.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtMemoryBitWrite.cs
new file mode 100644
index 0000000..48e9a99
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtMemoryBitWrite.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtMemoryBitWrite : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x10;
+
+        public ApduDataExtMemoryBitWrite()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtNetworkParameterRead.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtNetworkParameterRead.cs
new file mode 100644
index 0000000..c53cd41
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtNetworkParameterRead.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtNetworkParameterRead : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x1A;
+
+        public ApduDataExtNetworkParameterRead()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtNetworkParameterResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtNetworkParameterResponse.cs
new file mode 100644
index 0000000..9009e2f
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtNetworkParameterResponse.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtNetworkParameterResponse : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x1B;
+
+        public ApduDataExtNetworkParameterResponse()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtNetworkParameterWrite.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtNetworkParameterWrite.cs
new file mode 100644
index 0000000..3aa348b
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtNetworkParameterWrite.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtNetworkParameterWrite : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x24;
+
+        public ApduDataExtNetworkParameterWrite()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtOpenRoutingTableRequest.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtOpenRoutingTableRequest.cs
new file mode 100644
index 0000000..c29da56
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtOpenRoutingTableRequest.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtOpenRoutingTableRequest : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x00;
+
+        public ApduDataExtOpenRoutingTableRequest()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtPropertyDescriptionRead.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtPropertyDescriptionRead.cs
new file mode 100644
index 0000000..ec19fc8
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtPropertyDescriptionRead.cs
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtPropertyDescriptionRead : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x18;
+
+        // Properties.
+        public byte ObjectIndex { get; }
+        public byte PropertyId { get; }
+        public byte Index { get; }
+
+        public ApduDataExtPropertyDescriptionRead(byte objectIndex, byte propertyId, byte index)
+        {
+            ObjectIndex = objectIndex;
+            PropertyId = propertyId;
+            Index = index;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtPropertyDescriptionResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtPropertyDescriptionResponse.cs
new file mode 100644
index 0000000..2708884
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtPropertyDescriptionResponse.cs
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtPropertyDescriptionResponse : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x19;
+
+        // Properties.
+        public byte ObjectIndex { get; }
+        public byte PropertyId { get; }
+        public byte Index { get; }
+        public bool WriteEnabled { get; }
+        public KnxPropertyDataType PropertyDataType { get; }
+        public ushort MaxNrOfElements { get; }
+        public AccessLevel ReadLevel { get; }
+        public AccessLevel WriteLevel { get; }
+
+        public ApduDataExtPropertyDescriptionResponse(byte objectIndex, byte propertyId, byte index, bool writeEnabled, KnxPropertyDataType propertyDataType, ushort maxNrOfElements, AccessLevel readLevel, AccessLevel writeLevel)
+        {
+            ObjectIndex = objectIndex;
+            PropertyId = propertyId;
+            Index = index;
+            WriteEnabled = writeEnabled;
+            PropertyDataType = propertyDataType;
+            MaxNrOfElements = maxNrOfElements;
+            ReadLevel = readLevel;
+            WriteLevel = writeLevel;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtPropertyValueRead.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtPropertyValueRead.cs
new file mode 100644
index 0000000..853c9ed
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtPropertyValueRead.cs
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtPropertyValueRead : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x15;
+
+        // Properties.
+        public byte ObjectIndex { get; }
+        public byte PropertyId { get; }
+        public byte Count { get; }
+        public ushort Index { get; }
+
+        public ApduDataExtPropertyValueRead(byte objectIndex, byte propertyId, byte count, ushort index)
+        {
+            ObjectIndex = objectIndex;
+            PropertyId = propertyId;
+            Count = count;
+            Index = index;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtPropertyValueResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtPropertyValueResponse.cs
new file mode 100644
index 0000000..17ef7ad
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtPropertyValueResponse.cs
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtPropertyValueResponse : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x16;
+
+        // Properties.
+        public byte ObjectIndex { get; }
+        public byte PropertyId { get; }
+        public byte Count { get; }
+        public ushort Index { get; }
+        public byte[] Data { get; }
+
+        public ApduDataExtPropertyValueResponse(byte objectIndex, byte propertyId, byte count, ushort index, byte[] data)
+        {
+            ObjectIndex = objectIndex;
+            PropertyId = propertyId;
+            Count = count;
+            Index = index;
+            Data = data;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtPropertyValueWrite.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtPropertyValueWrite.cs
new file mode 100644
index 0000000..defc07e
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtPropertyValueWrite.cs
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtPropertyValueWrite : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x17;
+
+        // Properties.
+        public byte ObjectIndex { get; }
+        public byte PropertyId { get; }
+        public byte Count { get; }
+        public ushort Index { get; }
+        public byte[] Data { get; }
+
+        public ApduDataExtPropertyValueWrite(byte objectIndex, byte propertyId, byte count, ushort index, byte[] data)
+        {
+            ObjectIndex = objectIndex;
+            PropertyId = propertyId;
+            Count = count;
+            Index = index;
+            Data = data;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRouterMemoryRequest.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRouterMemoryRequest.cs
new file mode 100644
index 0000000..7e673c3
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRouterMemoryRequest.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtReadRouterMemoryRequest : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x08;
+
+        public ApduDataExtReadRouterMemoryRequest()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRouterMemoryResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRouterMemoryResponse.cs
new file mode 100644
index 0000000..ee2f825
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRouterMemoryResponse.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtReadRouterMemoryResponse : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x09;
+
+        public ApduDataExtReadRouterMemoryResponse()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRouterStatusRequest.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRouterStatusRequest.cs
new file mode 100644
index 0000000..4abf5e4
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRouterStatusRequest.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtReadRouterStatusRequest : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x0D;
+
+        public ApduDataExtReadRouterStatusRequest()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRouterStatusResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRouterStatusResponse.cs
new file mode 100644
index 0000000..9536b0f
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRouterStatusResponse.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtReadRouterStatusResponse : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x0E;
+
+        public ApduDataExtReadRouterStatusResponse()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRoutingTableRequest.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRoutingTableRequest.cs
new file mode 100644
index 0000000..6c5e42c
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRoutingTableRequest.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtReadRoutingTableRequest : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x01;
+
+        public ApduDataExtReadRoutingTableRequest()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRoutingTableResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRoutingTableResponse.cs
new file mode 100644
index 0000000..10caf24
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtReadRoutingTableResponse.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtReadRoutingTableResponse : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x02;
+
+        public ApduDataExtReadRoutingTableResponse()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtWriteRouterMemoryRequest.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtWriteRouterMemoryRequest.cs
new file mode 100644
index 0000000..70ef98f
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtWriteRouterMemoryRequest.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtWriteRouterMemoryRequest : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x0A;
+
+        public ApduDataExtWriteRouterMemoryRequest()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtWriteRouterStatusRequest.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtWriteRouterStatusRequest.cs
new file mode 100644
index 0000000..fa6b021
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtWriteRouterStatusRequest.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtWriteRouterStatusRequest : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x0F;
+
+        public ApduDataExtWriteRouterStatusRequest()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtWriteRoutingTableRequest.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtWriteRoutingTableRequest.cs
new file mode 100644
index 0000000..a9a42e1
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataExtWriteRoutingTableRequest.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataExtWriteRoutingTableRequest : ApduDataExt
+    {
+
+        // Accessors for discriminator values.
+        public override byte ExtApciType => 0x03;
+
+        public ApduDataExtWriteRoutingTableRequest()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataGroupValueRead.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataGroupValueRead.cs
new file mode 100644
index 0000000..7bfc343
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataGroupValueRead.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataGroupValueRead : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0x0;
+
+        public ApduDataGroupValueRead()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataGroupValueResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataGroupValueResponse.cs
new file mode 100644
index 0000000..ad91915
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataGroupValueResponse.cs
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataGroupValueResponse : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0x1;
+
+        // Properties.
+        public sbyte DataFirstByte { get; }
+        public byte[] Data { get; }
+
+        public ApduDataGroupValueResponse(sbyte dataFirstByte, byte[] data)
+        {
+            DataFirstByte = dataFirstByte;
+            Data = data;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataGroupValueWrite.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataGroupValueWrite.cs
new file mode 100644
index 0000000..5d46503
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataGroupValueWrite.cs
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataGroupValueWrite : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0x2;
+
+        // Properties.
+        public sbyte DataFirstByte { get; }
+        public byte[] Data { get; }
+
+        public ApduDataGroupValueWrite(sbyte dataFirstByte, byte[] data)
+        {
+            DataFirstByte = dataFirstByte;
+            Data = data;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataIndividualAddressRead.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataIndividualAddressRead.cs
new file mode 100644
index 0000000..dade850
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataIndividualAddressRead.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataIndividualAddressRead : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0x4;
+
+        public ApduDataIndividualAddressRead()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataIndividualAddressResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataIndividualAddressResponse.cs
new file mode 100644
index 0000000..aad45ec
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataIndividualAddressResponse.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataIndividualAddressResponse : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0x5;
+
+        public ApduDataIndividualAddressResponse()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataIndividualAddressWrite.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataIndividualAddressWrite.cs
new file mode 100644
index 0000000..25e9bf3
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataIndividualAddressWrite.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataIndividualAddressWrite : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0x3;
+
+        public ApduDataIndividualAddressWrite()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataMemoryRead.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataMemoryRead.cs
new file mode 100644
index 0000000..80c715f
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataMemoryRead.cs
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataMemoryRead : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0x8;
+
+        // Properties.
+        public byte NumBytes { get; }
+        public ushort Address { get; }
+
+        public ApduDataMemoryRead(byte numBytes, ushort address)
+        {
+            NumBytes = numBytes;
+            Address = address;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataMemoryResponse.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataMemoryResponse.cs
new file mode 100644
index 0000000..7a961cf
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataMemoryResponse.cs
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataMemoryResponse : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0x9;
+
+        // Properties.
+        public ushort Address { get; }
+        public byte[] Data { get; }
+
+        public ApduDataMemoryResponse(ushort address, byte[] data)
+        {
+            Address = address;
+            Data = data;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataMemoryWrite.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataMemoryWrite.cs
new file mode 100644
index 0000000..1bbdb09
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataMemoryWrite.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataMemoryWrite : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0xA;
+
+        public ApduDataMemoryWrite()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataOther.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataOther.cs
new file mode 100644
index 0000000..ef9d970
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataOther.cs
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataOther : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0xF;
+
+        // Properties.
+        public ApduDataExt ExtendedApdu { get; }
+
+        public ApduDataOther(ApduDataExt extendedApdu)
+        {
+            ExtendedApdu = extendedApdu;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataRestart.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataRestart.cs
new file mode 100644
index 0000000..2cae6d2
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataRestart.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataRestart : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0xE;
+
+        public ApduDataRestart()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataUserMessage.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataUserMessage.cs
new file mode 100644
index 0000000..4c16f63
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ApduDataUserMessage.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ApduDataUserMessage : ApduData
+    {
+
+        // Accessors for discriminator values.
+        public override byte ApciType => 0xB;
+
+        public ApduDataUserMessage()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/CEMI.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/CEMI.cs
new file mode 100644
index 0000000..947f5f9
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/CEMI.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public abstract class CEMI
+    {
+
+        // Abstract accessors for discriminator values.
+        public abstract byte MessageCode { get; }
+
+        public CEMI()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/CEMIAdditionalInformation.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/CEMIAdditionalInformation.cs
new file mode 100644
index 0000000..36fbc33
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/CEMIAdditionalInformation.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public abstract class CEMIAdditionalInformation
+    {
+
+        // Abstract accessors for discriminator values.
+        public abstract byte AdditionalInformationType { get; }
+
+        public CEMIAdditionalInformation()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/CEMIAdditionalInformationBusmonitorInfo.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/CEMIAdditionalInformationBusmonitorInfo.cs
new file mode 100644
index 0000000..67997e9
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/CEMIAdditionalInformationBusmonitorInfo.cs
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class CEMIAdditionalInformationBusmonitorInfo : CEMIAdditionalInformation
+    {
+
+        // Accessors for discriminator values.
+        public override byte AdditionalInformationType => 0x03;
+
+        // Constant values.
+        public const byte LEN = 1;
+
+        // Properties.
+        public bool FrameErrorFlag { get; }
+        public bool BitErrorFlag { get; }
+        public bool ParityErrorFlag { get; }
+        public bool UnknownFlag { get; }
+        public bool LostFlag { get; }
+        public byte SequenceNumber { get; }
+
+        public CEMIAdditionalInformationBusmonitorInfo(bool frameErrorFlag, bool bitErrorFlag, bool parityErrorFlag, bool unknownFlag, bool lostFlag, byte sequenceNumber)
+        {
+            FrameErrorFlag = frameErrorFlag;
+            BitErrorFlag = bitErrorFlag;
+            ParityErrorFlag = parityErrorFlag;
+            UnknownFlag = unknownFlag;
+            LostFlag = lostFlag;
+            SequenceNumber = sequenceNumber;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/CEMIAdditionalInformationRelativeTimestamp.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/CEMIAdditionalInformationRelativeTimestamp.cs
new file mode 100644
index 0000000..9bc7f9d
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/CEMIAdditionalInformationRelativeTimestamp.cs
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class CEMIAdditionalInformationRelativeTimestamp : CEMIAdditionalInformation
+    {
+
+        // Accessors for discriminator values.
+        public override byte AdditionalInformationType => 0x04;
+
+        // Constant values.
+        public const byte LEN = 2;
+
+        // Properties.
+        public RelativeTimestamp RelativeTimestamp { get; }
+
+        public CEMIAdditionalInformationRelativeTimestamp(RelativeTimestamp relativeTimestamp)
+        {
+            RelativeTimestamp = relativeTimestamp;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/CEMIPriority.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/CEMIPriority.cs
new file mode 100644
index 0000000..51681b4
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/CEMIPriority.cs
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public enum CEMIPriority
+    {
+        SYSTEM = 0x0,
+        NORMAL = 0x1,
+        URGENT = 0x2,
+        LOW = 0x3,
+    }
+
+}
+
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ChannelInformation.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ChannelInformation.cs
new file mode 100644
index 0000000..b486594
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ChannelInformation.cs
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class ChannelInformation
+    {
+
+
+        // Properties.
+        public byte NumChannels { get; }
+        public ushort ChannelCode { get; }
+
+        public ChannelInformation(byte numChannels, ushort channelCode)
+        {
+            NumChannels = numChannels;
+            ChannelCode = channelCode;
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ComObjectTable.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ComObjectTable.cs
new file mode 100644
index 0000000..fd403bd
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ComObjectTable.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public abstract class ComObjectTable
+    {
+
+        // Abstract accessors for discriminator values.
+        public abstract FirmwareType FirmwareType { get; }
+
+        public ComObjectTable()
+        {
+        }
+
+    }
+}
diff --git a/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ComObjectTableAddresses.cs b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ComObjectTableAddresses.cs
new file mode 100644
index 0000000..2cc7b5b
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/ComObjectTableAddresses.cs
@@ -0,0 +1,7416 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Code generated by code-generation. DO NOT EDIT.
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public enum ComObjectTableAddresses
+    {
+        DEV0001914201 = 1,
+        DEV0001140C13 = 2,
+        DEV0001140B11 = 3,
+        DEV0001803002 = 4,
+        DEV00641BD610 = 5,
+        DEV0064760210 = 6,
+        DEV0064182410 = 7,
+        DEV0064182310 = 8,
+        DEV0064705C01 = 9,
+        DEV0064181910 = 10,
+        DEV0064181810 = 11,
+        DEV0064181710 = 12,
+        DEV0064181610 = 13,
+        DEV006420C011 = 14,
+        DEV006420BA11 = 15,
+        DEV0064182010 = 16,
+        DEV0064182510 = 17,
+        DEV0064182610 = 18,
+        DEV0064182910 = 19,
+        DEV0064130610 = 20,
+        DEV0064130710 = 21,
+        DEV0064133510 = 22,
+        DEV0064133310 = 23,
+        DEV0064133410 = 24,
+        DEV0064133610 = 25,
+        DEV0064130510 = 26,
+        DEV0064480611 = 27,
+        DEV0064482011 = 28,
+        DEV0064182210 = 29,
+        DEV0064182710 = 30,
+        DEV0064183010 = 31,
+        DEV0064B00812 = 32,
+        DEV0064B00A01 = 33,
+        DEV0064760110 = 34,
+        DEV0064242313 = 35,
+        DEV0064FF2111 = 36,
+        DEV0064FF2112 = 37,
+        DEV0064648B10 = 38,
+        DEV0064724010 = 39,
+        DEV006420BD11 = 40,
+        DEV0064570011 = 41,
+        DEV0064570310 = 42,
+        DEV0064570211 = 43,
+        DEV0064570411 = 44,
+        DEV0064570110 = 45,
+        DEV0064615022 = 46,
+        DEV0064182810 = 47,
+        DEV0064183110 = 48,
+        DEV0064133611 = 49,
+        DEV006A000122 = 50,
+        DEV006A000222 = 51,
+        DEV006A070210 = 52,
+        DEV006BFFF713 = 53,
+        DEV006BFF2111 = 54,
+        DEV006BFFF820 = 55,
+        DEV006B106D10 = 56,
+        DEV0071123130 = 57,
+        DEV0071413133 = 58,
+        DEV0071114019 = 59,
+        DEV007111306C = 60,
+        DEV0071231112 = 61,
+        DEV0071113080 = 62,
+        DEV0071321212 = 63,
+        DEV0071321113 = 64,
+        DEV0071322212 = 65,
+        DEV0071322112 = 66,
+        DEV0071322312 = 67,
+        DEV0071122124 = 68,
+        DEV0071122135 = 69,
+        DEV007112221E = 70,
+        DEV0071122229 = 71,
+        DEV0071413314 = 72,
+        DEV0072300110 = 73,
+        DEV0076002101 = 74,
+        DEV0076002001 = 75,
+        DEV0076002A15 = 76,
+        DEV0076002815 = 77,
+        DEV0076002215 = 78,
+        DEV0076002B15 = 79,
+        DEV0076002715 = 80,
+        DEV0076002315 = 81,
+        DEV0076002415 = 82,
+        DEV0076002615 = 83,
+        DEV0076002515 = 84,
+        DEV0076000201 = 85,
+        DEV0076000101 = 86,
+        DEV0076000301 = 87,
+        DEV0076000401 = 88,
+        DEV0076002903 = 89,
+        DEV0076002901 = 90,
+        DEV007600E503 = 91,
+        DEV0076004002 = 92,
+        DEV0076004003 = 93,
+        DEV0076003402 = 94,
+        DEV0076003401 = 95,
+        DEV007600E908 = 96,
+        DEV007600E907 = 97,
+        DEV000C181710 = 98,
+        DEV000C130510 = 99,
+        DEV000C130610 = 100,
+        DEV000C133610 = 101,
+        DEV000C133410 = 102,
+        DEV000C133310 = 103,
+        DEV000C133611 = 104,
+        DEV000C133510 = 105,
+        DEV000C130710 = 106,
+        DEV000C760210 = 107,
+        DEV000C1BD610 = 108,
+        DEV000C181610 = 109,
+        DEV000C648B10 = 110,
+        DEV000C480611 = 111,
+        DEV000C482011 = 112,
+        DEV000C724010 = 113,
+        DEV000C570211 = 114,
+        DEV000C570310 = 115,
+        DEV000C570411 = 116,
+        DEV000C570110 = 117,
+        DEV000C570011 = 118,
+        DEV000C20BD11 = 119,
+        DEV000C20BA11 = 120,
+        DEV000C760110 = 121,
+        DEV000C705C01 = 122,
+        DEV000CFF2112 = 123,
+        DEV000C242313 = 124,
+        DEV000CB00812 = 125,
+        DEV000CB00713 = 126,
+        DEV000C181910 = 127,
+        DEV000C181810 = 128,
+        DEV000C20C011 = 129,
+        DEV0079002527 = 130,
+        DEV0079004027 = 131,
+        DEV0079000223 = 132,
+        DEV0079000123 = 133,
+        DEV0079001427 = 134,
+        DEV0079003027 = 135,
+        DEV0079100C13 = 136,
+        DEV0079101C11 = 137,
+        DEV0080709010 = 138,
+        DEV0080707010 = 139,
+        DEV0080706010 = 140,
+        DEV0080706810 = 141,
+        DEV0080705010 = 142,
+        DEV0080703013 = 143,
+        DEV0080704021 = 144,
+        DEV0080704022 = 145,
+        DEV0080704020 = 146,
+        DEV0080701111 = 147,
+        DEV0080701811 = 148,
+        DEV008020A110 = 149,
+        DEV008020A210 = 150,
+        DEV008020A010 = 151,
+        DEV0080207212 = 152,
+        DEV0080209111 = 153,
+        DEV0080204310 = 154,
+        DEV008020B612 = 155,
+        DEV008020B412 = 156,
+        DEV008020B512 = 157,
+        DEV0080208310 = 158,
+        DEV0080702111 = 159,
+        DEV0085000520 = 160,
+        DEV0085000620 = 161,
+        DEV0085000720 = 162,
+        DEV0085012210 = 163,
+        DEV0085011210 = 164,
+        DEV0085013220 = 165,
+        DEV0085010210 = 166,
+        DEV0085000A10 = 167,
+        DEV0085000B10 = 168,
+        DEV0085071010 = 169,
+        DEV008500FB10 = 170,
+        DEV0085060210 = 171,
+        DEV0085060110 = 172,
+        DEV0085000D20 = 173,
+        DEV008500C810 = 174,
+        DEV0085040111 = 175,
+        DEV008500C910 = 176,
+        DEV0085045020 = 177,
+        DEV0085070210 = 178,
+        DEV0085070110 = 179,
+        DEV0085070310 = 180,
+        DEV0085000E20 = 181,
+        DEV008E596010 = 182,
+        DEV008E593710 = 183,
+        DEV008E597710 = 184,
+        DEV008E598310 = 185,
+        DEV008E598910 = 186,
+        DEV008E598920 = 187,
+        DEV008E598320 = 188,
+        DEV008E596021 = 189,
+        DEV008E597721 = 190,
+        DEV008E587320 = 191,
+        DEV008E587020 = 192,
+        DEV008E587220 = 193,
+        DEV008E587120 = 194,
+        DEV008E679910 = 195,
+        DEV008E618310 = 196,
+        DEV008E707910 = 197,
+        DEV008E676610 = 198,
+        DEV008E004010 = 199,
+        DEV008E570910 = 200,
+        DEV008E558810 = 201,
+        DEV008E683410 = 202,
+        DEV008E707710 = 203,
+        DEV008E707810 = 204,
+        DEV008E787310 = 205,
+        DEV008E787410 = 206,
+        DEV0091100013 = 207,
+        DEV0091100110 = 208,
+        DEV009E670101 = 209,
+        DEV009E119311 = 210,
+        DEV00A2101C11 = 211,
+        DEV00A2100C13 = 212,
+        DEV00A2300110 = 213,
+        DEV0002A05814 = 214,
+        DEV0002A07114 = 215,
+        DEV0002134A10 = 216,
+        DEV0002A03D12 = 217,
+        DEV0002A03422 = 218,
+        DEV0002A03321 = 219,
+        DEV0002648B10 = 220,
+        DEV0002A09013 = 221,
+        DEV0002A08F13 = 222,
+        DEV0002A05510 = 223,
+        DEV0002A05910 = 224,
+        DEV0002A05326 = 225,
+        DEV0002A05428 = 226,
+        DEV0002A08411 = 227,
+        DEV0002A08511 = 228,
+        DEV0002A00F11 = 229,
+        DEV0002A07310 = 230,
+        DEV0002A04110 = 231,
+        DEV0002A06414 = 232,
+        DEV0002A03813 = 233,
+        DEV0002A07F13 = 234,
+        DEV0002A01217 = 235,
+        DEV0002A07914 = 236,
+        DEV0002A06114 = 237,
+        DEV0002A06714 = 238,
+        DEV0002A06214 = 239,
+        DEV0002A06514 = 240,
+        DEV0002A07714 = 241,
+        DEV0002A06014 = 242,
+        DEV0002A06614 = 243,
+        DEV0002A07814 = 244,
+        DEV0002A09A13 = 245,
+        DEV0002A00213 = 246,
+        DEV0002A00113 = 247,
+        DEV0002A01511 = 248,
+        DEV0002A01112 = 249,
+        DEV0002FF1140 = 250,
+        DEV0002A07E10 = 251,
+        DEV0002A07213 = 252,
+        DEV0002A04A35 = 253,
+        DEV0002613812 = 254,
+        DEV0002A07420 = 255,
+        DEV0002A07520 = 256,
+        DEV0002A07B12 = 257,
+        DEV0002A07C12 = 258,
+        DEV0002A04312 = 259,
+        DEV0002A04412 = 260,
+        DEV0002A04512 = 261,
+        DEV0002A04912 = 262,
+        DEV0002A05012 = 263,
+        DEV0002A01811 = 264,
+        DEV0002A03E11 = 265,
+        DEV0002A08711 = 266,
+        DEV0002A09311 = 267,
+        DEV0002A01011 = 268,
+        DEV0002A01622 = 269,
+        DEV0002A04210 = 270,
+        DEV0002A0C310 = 271,
+        DEV0002A0C316 = 272,
+        DEV0002A04B10 = 273,
+        DEV0002A09B12 = 274,
+        DEV0002A04F13 = 275,
+        DEV0002A04D13 = 276,
+        DEV0002A04C13 = 277,
+        DEV0002A04E13 = 278,
+        DEV0002A09C12 = 279,
+        DEV0002A03C10 = 280,
+        DEV0002A0A511 = 281,
+        DEV0002A0A516 = 282,
+        DEV0002A0A514 = 283,
+        DEV0002A0A513 = 284,
+        DEV0002A0A512 = 285,
+        DEV0002A0A611 = 286,
+        DEV0002A0A616 = 287,
+        DEV0002A09111 = 288,
+        DEV0002A09211 = 289,
+        DEV0002632010 = 290,
+        DEV0002632020 = 291,
+        DEV0002632170 = 292,
+        DEV0002632040 = 293,
+        DEV00C8272040 = 294,
+        DEV00C8272260 = 295,
+        DEV00C8272060 = 296,
+        DEV00C8272160 = 297,
+        DEV00C8272050 = 298,
+        DEV00C910BA10 = 299,
+        DEV00C9106D10 = 300,
+        DEV00C9107C20 = 301,
+        DEV00C9108511 = 302,
+        DEV00C9108500 = 303,
+        DEV00C9106210 = 304,
+        DEV00C9109310 = 305,
+        DEV00C9109300 = 306,
+        DEV00C9109210 = 307,
+        DEV00C9109200 = 308,
+        DEV00C9109810 = 309,
+        DEV00C9109A10 = 310,
+        DEV00C9109A00 = 311,
+        DEV00C910A420 = 312,
+        DEV00C910A110 = 313,
+        DEV00C910A100 = 314,
+        DEV00C910A010 = 315,
+        DEV00C910A000 = 316,
+        DEV00C910A310 = 317,
+        DEV00C910A300 = 318,
+        DEV00C910A210 = 319,
+        DEV00C910A200 = 320,
+        DEV00C9109B10 = 321,
+        DEV00C9109B00 = 322,
+        DEV00C9106110 = 323,
+        DEV00C9109110 = 324,
+        DEV00C9109100 = 325,
+        DEV00C9109610 = 326,
+        DEV00C9109600 = 327,
+        DEV00C9109710 = 328,
+        DEV00C9109700 = 329,
+        DEV00C9109510 = 330,
+        DEV00C9109500 = 331,
+        DEV00C9109910 = 332,
+        DEV00C9109900 = 333,
+        DEV00C9109C10 = 334,
+        DEV00C9109C00 = 335,
+        DEV00C910AB10 = 336,
+        DEV00C910AB00 = 337,
+        DEV00C910AC10 = 338,
+        DEV00C910AC00 = 339,
+        DEV00C910AD10 = 340,
+        DEV00C910AD00 = 341,
+        DEV00C910A810 = 342,
+        DEV00C910B010 = 343,
+        DEV00C910B310 = 344,
+        DEV00C9106311 = 345,
+        DEV00C9106111 = 346,
+        DEV00C9106510 = 347,
+        DEV00C910A710 = 348,
+        DEV00C9107610 = 349,
+        DEV00C910AF10 = 350,
+        DEV00C910B510 = 351,
+        DEV00C910890A = 352,
+        DEV00C9FF1012 = 353,
+        DEV00C9FF0913 = 354,
+        DEV00C9FF1112 = 355,
+        DEV00C9100310 = 356,
+        DEV00C9101110 = 357,
+        DEV00C9101010 = 358,
+        DEV00C9103710 = 359,
+        DEV00C9101310 = 360,
+        DEV00C9FF0D12 = 361,
+        DEV00C9100E10 = 362,
+        DEV00C9100610 = 363,
+        DEV00C9100510 = 364,
+        DEV00C9100710 = 365,
+        DEV00C9FF1D20 = 366,
+        DEV00C9FF1C10 = 367,
+        DEV00C9100810 = 368,
+        DEV00C9FF1420 = 369,
+        DEV00C9100D10 = 370,
+        DEV00C9101220 = 371,
+        DEV00C9102330 = 372,
+        DEV00C9102130 = 373,
+        DEV00C9102430 = 374,
+        DEV00C9100831 = 375,
+        DEV00C9102530 = 376,
+        DEV00C9100531 = 377,
+        DEV00C9102030 = 378,
+        DEV00C9100731 = 379,
+        DEV00C9100631 = 380,
+        DEV00C9102230 = 381,
+        DEV00C9100632 = 382,
+        DEV00C9100532 = 383,
+        DEV00C9100732 = 384,
+        DEV00C9100832 = 385,
+        DEV00C9102532 = 386,
+        DEV00C9102132 = 387,
+        DEV00C9102332 = 388,
+        DEV00C9102432 = 389,
+        DEV00C9102032 = 390,
+        DEV00C9102232 = 391,
+        DEV00C9104432 = 392,
+        DEV00C9100D11 = 393,
+        DEV00C9100633 = 394,
+        DEV00C9100533 = 395,
+        DEV00C9100733 = 396,
+        DEV00C9100833 = 397,
+        DEV00C9102533 = 398,
+        DEV00C9102133 = 399,
+        DEV00C9102333 = 400,
+        DEV00C9102433 = 401,
+        DEV00C9102033 = 402,
+        DEV00C9102233 = 403,
+        DEV00C9104810 = 404,
+        DEV00C9FF1A11 = 405,
+        DEV00C9100212 = 406,
+        DEV00C9FF0A11 = 407,
+        DEV00C9FF0C12 = 408,
+        DEV00C9100112 = 409,
+        DEV00C9FF1911 = 410,
+        DEV00C9FF0B12 = 411,
+        DEV00C9FF0715 = 412,
+        DEV00C9FF1B10 = 413,
+        DEV00C9101610 = 414,
+        DEV00C9FF1B11 = 415,
+        DEV00C9101611 = 416,
+        DEV00C9101612 = 417,
+        DEV00C9FF0F11 = 418,
+        DEV00C910B710 = 419,
+        DEV00C9FF1E30 = 420,
+        DEV00C9100410 = 421,
+        DEV00C9106410 = 422,
+        DEV00C9106710 = 423,
+        DEV00C9106700 = 424,
+        DEV00C9106810 = 425,
+        DEV00C9106800 = 426,
+        DEV00C9106010 = 427,
+        DEV00C9106000 = 428,
+        DEV00C9106310 = 429,
+        DEV00C9107110 = 430,
... 45174 lines suppressed ...