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

[plc4x] branch develop updated: refactor(plc4go): restructured package (+moved protocols to a public importable place)

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

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


The following commit(s) were added to refs/heads/develop by this push:
     new adc23d2f9d refactor(plc4go): restructured package (+moved protocols to a public importable place)
adc23d2f9d is described below

commit adc23d2f9d0caa8c901e49e1621107dfd44cc45c
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Mon May 23 13:10:41 2022 +0200

    refactor(plc4go): restructured package (+moved protocols to a public importable place)
---
 .../language/go/GoLanguageTemplateHelper.java      |     2 +-
 .../apache/plc4x/language/go/utils/FieldUtils.java |   103 -
 .../templates/go/complex-type-template.go.ftlh     |     2 +-
 .../templates/go/data-io-template.go.ftlh          |     2 +-
 .../resources/templates/go/enum-template.go.ftlh   |     2 +-
 .../templates/go/parser-factory-template.go.ftlh   |     4 +-
 .../go/xml-parser-factory-template.go.ftlh         |     4 +-
 .../plc4go/test/readwrite/model/StaticHelper.go    |     2 +-
 .../language-go/src/test/resources/plc4go/pom.xml  |     2 +-
 plc4go/cmd/main/drivers/s7_test.go                 |     4 +-
 plc4go/cmd/main/drivers/tests/abeth_driver_test.go |     6 +-
 .../drivers/tests/abeth_parser_serializer_test.go  |     2 +-
 plc4go/cmd/main/drivers/tests/ads_driver_test.go   |    10 +-
 .../drivers/tests/ads_parser_serializer_test.go    |     2 +-
 .../drivers/tests/bacnet_parser_serializer_test.go |     2 +-
 plc4go/cmd/main/drivers/tests/df1_driver_test.go   |     6 +-
 .../drivers/tests/df1_parser_serializer_test.go    |     2 +-
 plc4go/cmd/main/drivers/tests/eip_driver_test.go   |    10 +-
 .../drivers/tests/eip_parser_serializer_test.go    |     2 +-
 .../cmd/main/drivers/tests/firmata_driver_test.go  |     6 +-
 .../tests/firmata_parser_serializer_test.go        |     2 +-
 .../cmd/main/drivers/tests/knxnetip_driver_test.go |    10 +-
 .../tests/knxnetip_parser_serializer_test.go       |     2 +-
 .../main/drivers/tests/manual_ads_driver_test.go   |     4 +-
 .../drivers/tests/manual_bacnet_PcapTest_test.go   |     6 +-
 .../main/drivers/tests/manual_s7_driver_test.go    |     4 +-
 .../cmd/main/drivers/tests/modbus_driver_test.go   |    10 +-
 .../drivers/tests/modbus_parser_serializer_test.go |     2 +-
 plc4go/cmd/main/drivers/tests/s7_driver_test.go    |    10 +-
 .../drivers/tests/s7_parser_serializer_test.go     |     2 +-
 .../discovery/hello_world_plc4go_knx_discovery.go  |     2 +-
 plc4go/internal/ads/Configuration.go               |   147 +
 plc4go/internal/ads/Connection.go                  |   136 +
 plc4go/internal/ads/Driver.go                      |    87 +
 plc4go/internal/ads/Field.go                       |   216 +
 plc4go/internal/ads/FieldHandler.go                |   162 +
 plc4go/internal/ads/MessageCodec.go                |   101 +
 plc4go/internal/ads/Reader.go                      |   432 +
 plc4go/internal/ads/ValueHandler.go                |    32 +
 plc4go/internal/ads/Writer.go                      |   216 +
 .../internal/{plc4go => }/ads/fieldtype_string.go  |     0
 plc4go/internal/bacnetip/Connection.go             |   118 +
 plc4go/internal/bacnetip/Driver.go                 |    77 +
 plc4go/internal/bacnetip/Field.go                  |    92 +
 plc4go/internal/bacnetip/FieldHandler.go           |    88 +
 plc4go/internal/bacnetip/MessageCodec.go           |   107 +
 plc4go/internal/bacnetip/Subscriber.go             |    71 +
 plc4go/internal/bacnetip/ValueHandler.go           |    32 +
 plc4go/internal/{plc4go => }/eip/Configuration.go  |     0
 plc4go/internal/eip/Connection.go                  |   208 +
 plc4go/internal/eip/Driver.go                      |   110 +
 plc4go/internal/{plc4go => }/eip/DriverContext.go  |     0
 plc4go/internal/eip/Field.go                       |    99 +
 plc4go/internal/eip/FieldHandler.go                |    56 +
 plc4go/internal/eip/MessageCodec.go                |   102 +
 plc4go/internal/eip/Reader.go                      |   541 +
 plc4go/internal/eip/ValueHandler.go                |    32 +
 plc4go/internal/eip/Writer.go                      |   361 +
 plc4go/internal/knxnetip/Browser.go                |   703 +
 plc4go/internal/knxnetip/Connection.go             |   494 +
 .../knxnetip/ConnectionDriverSpecificOperations.go |   521 +
 plc4go/internal/knxnetip/ConnectionHelper.go       |   237 +
 .../knxnetip/ConnectionInternalOperations.go       |  1183 +
 plc4go/internal/knxnetip/Discoverer.go             |   190 +
 plc4go/internal/knxnetip/Driver.go                 |    82 +
 plc4go/internal/knxnetip/Field.go                  |   468 +
 plc4go/internal/knxnetip/FieldHandler.go           |   132 +
 plc4go/internal/knxnetip/MessageCodec.go           |   140 +
 plc4go/internal/knxnetip/Reader.go                 |   351 +
 plc4go/internal/knxnetip/Subscriber.go             |   178 +
 plc4go/internal/knxnetip/SubscriptionEvent.go      |    68 +
 plc4go/internal/knxnetip/Utils.go                  |   102 +
 plc4go/internal/knxnetip/ValueDecoder.go           |    45 +
 .../internal/{plc4go => }/knxnetip/ValueHandler.go |     0
 plc4go/internal/knxnetip/Writer.go                 |    73 +
 plc4go/internal/modbus/Connection.go               |   154 +
 plc4go/internal/modbus/Field.go                    |   112 +
 plc4go/internal/modbus/FieldHandler.go             |    99 +
 plc4go/internal/modbus/MessageCodec.go             |   104 +
 plc4go/internal/modbus/ModbusAsciiDriver.go        |   102 +
 plc4go/internal/modbus/ModbusRtuDriver.go          |   102 +
 plc4go/internal/modbus/ModbusTcpDriver.go          |   102 +
 plc4go/internal/modbus/Reader.go                   |   217 +
 plc4go/internal/modbus/ValueHandler.go             |    32 +
 plc4go/internal/modbus/Writer.go                   |   224 +
 .../{plc4go => }/modbus/fieldtype_string.go        |     0
 .../plc4go/abeth/readwrite/ParserHelper.go         |    49 -
 .../plc4go/abeth/readwrite/XmlParserHelper.go      |    60 -
 .../model/CIPEncapsulationConnectionRequest.go     |   158 -
 .../model/CIPEncapsulationConnectionResponse.go    |   158 -
 .../readwrite/model/CIPEncapsulationPacket.go      |   361 -
 .../readwrite/model/CIPEncapsulationReadRequest.go |   206 -
 .../model/CIPEncapsulationReadResponse.go          |   209 -
 .../readwrite/model/DF1CommandRequestMessage.go    |   206 -
 ...mandResponseMessageProtectedTypedLogicalRead.go |   223 -
 .../abeth/readwrite/model/DF1RequestCommand.go     |   183 -
 .../abeth/readwrite/model/DF1RequestMessage.go     |   315 -
 .../model/DF1RequestProtectedTypedLogicalRead.go   |   294 -
 .../abeth/readwrite/model/DF1ResponseMessage.go    |   343 -
 plc4go/internal/plc4go/ads/Configuration.go        |   147 -
 plc4go/internal/plc4go/ads/Connection.go           |   136 -
 plc4go/internal/plc4go/ads/Driver.go               |    87 -
 plc4go/internal/plc4go/ads/Field.go                |   216 -
 plc4go/internal/plc4go/ads/FieldHandler.go         |   162 -
 plc4go/internal/plc4go/ads/MessageCodec.go         |   101 -
 plc4go/internal/plc4go/ads/Reader.go               |   432 -
 plc4go/internal/plc4go/ads/ValueHandler.go         |    32 -
 plc4go/internal/plc4go/ads/Writer.go               |   216 -
 .../internal/plc4go/ads/readwrite/ParserHelper.go  |    78 -
 .../plc4go/ads/readwrite/XmlParserHelper.go        |    85 -
 .../model/AdsAddDeviceNotificationRequest.go       |   375 -
 .../model/AdsAddDeviceNotificationResponse.go      |   231 -
 .../internal/plc4go/ads/readwrite/model/AdsData.go |   207 -
 .../plc4go/ads/readwrite/model/AdsDataType.go      |   783 -
 .../model/AdsDeleteDeviceNotificationRequest.go    |   194 -
 .../model/AdsDeleteDeviceNotificationResponse.go   |   205 -
 .../model/AdsDeviceNotificationRequest.go          |   272 -
 .../model/AdsDeviceNotificationResponse.go         |   157 -
 .../ads/readwrite/model/AdsInvalidRequest.go       |   157 -
 .../ads/readwrite/model/AdsInvalidResponse.go      |   157 -
 .../ads/readwrite/model/AdsMultiRequestItem.go     |   171 -
 .../ads/readwrite/model/AdsMultiRequestItemRead.go |   242 -
 .../model/AdsMultiRequestItemReadWrite.go          |   268 -
 .../readwrite/model/AdsMultiRequestItemWrite.go    |   242 -
 .../ads/readwrite/model/AdsNotificationSample.go   |   200 -
 .../readwrite/model/AdsReadDeviceInfoRequest.go    |   157 -
 .../readwrite/model/AdsReadDeviceInfoResponse.go   |   312 -
 .../plc4go/ads/readwrite/model/AdsReadRequest.go   |   246 -
 .../plc4go/ads/readwrite/model/AdsReadResponse.go  |   251 -
 .../ads/readwrite/model/AdsReadStateRequest.go     |   157 -
 .../ads/readwrite/model/AdsReadStateResponse.go    |   257 -
 .../ads/readwrite/model/AdsReadWriteRequest.go     |   344 -
 .../ads/readwrite/model/AdsReadWriteResponse.go    |   251 -
 .../plc4go/ads/readwrite/model/AdsStampHeader.go   |   223 -
 .../ads/readwrite/model/AdsWriteControlRequest.go  |   266 -
 .../ads/readwrite/model/AdsWriteControlResponse.go |   205 -
 .../plc4go/ads/readwrite/model/AdsWriteRequest.go  |   266 -
 .../plc4go/ads/readwrite/model/AdsWriteResponse.go |   205 -
 .../plc4go/ads/readwrite/model/AmsNetId.go         |   269 -
 .../plc4go/ads/readwrite/model/AmsPacket.go        |   413 -
 .../readwrite/model/AmsSerialAcknowledgeFrame.go   |   269 -
 .../plc4go/ads/readwrite/model/AmsSerialFrame.go   |   304 -
 .../ads/readwrite/model/AmsSerialResetFrame.go     |   269 -
 .../plc4go/ads/readwrite/model/AmsTCPPacket.go     |   203 -
 .../plc4go/ads/readwrite/model/CommandId.go        |   186 -
 .../plc4go/ads/readwrite/model/DataItem.go         |   369 -
 .../ads/readwrite/model/ReservedIndexGroups.go     |   346 -
 .../plc4go/ads/readwrite/model/ReturnCode.go       |  1082 -
 .../internal/plc4go/ads/readwrite/model/State.go   |   367 -
 .../plc4go/ads/readwrite/model/StaticHelper.go     |    47 -
 plc4go/internal/plc4go/bacnetip/Connection.go      |   118 -
 plc4go/internal/plc4go/bacnetip/Driver.go          |    77 -
 plc4go/internal/plc4go/bacnetip/Field.go           |    92 -
 plc4go/internal/plc4go/bacnetip/FieldHandler.go    |    88 -
 plc4go/internal/plc4go/bacnetip/MessageCodec.go    |   107 -
 plc4go/internal/plc4go/bacnetip/Subscriber.go      |    71 -
 plc4go/internal/plc4go/bacnetip/ValueHandler.go    |    32 -
 .../plc4go/bacnetip/readwrite/ParserHelper.go      |   927 -
 .../plc4go/bacnetip/readwrite/XmlParserHelper.go   |  1057 -
 .../plc4go/bacnetip/readwrite/model/APDU.go        |   202 -
 .../plc4go/bacnetip/readwrite/model/APDUAbort.go   |   282 -
 .../bacnetip/readwrite/model/APDUComplexAck.go     |   463 -
 .../readwrite/model/APDUConfirmedRequest.go        |   563 -
 .../plc4go/bacnetip/readwrite/model/APDUError.go   |   293 -
 .../plc4go/bacnetip/readwrite/model/APDUReject.go  |   256 -
 .../bacnetip/readwrite/model/APDUSegmentAck.go     |   323 -
 .../bacnetip/readwrite/model/APDUSimpleAck.go      |   245 -
 .../readwrite/model/APDUUnconfirmedRequest.go      |   230 -
 .../plc4go/bacnetip/readwrite/model/APDUUnknown.go |   196 -
 .../bacnetip/readwrite/model/BACnetAbortReason.go  |   210 -
 .../readwrite/model/BACnetAbortReasonTagged.go     |   200 -
 .../BACnetAccessAuthenticationFactorDisable.go     |   162 -
 ...ACnetAccessAuthenticationFactorDisableTagged.go |   246 -
 .../model/BACnetAccessCredentialDisable.go         |   146 -
 .../model/BACnetAccessCredentialDisableReason.go   |   194 -
 .../BACnetAccessCredentialDisableReasonTagged.go   |   246 -
 .../model/BACnetAccessCredentialDisableTagged.go   |   246 -
 .../bacnetip/readwrite/model/BACnetAccessEvent.go  |   546 -
 .../readwrite/model/BACnetAccessEventTagged.go     |   246 -
 .../readwrite/model/BACnetAccessPassbackMode.go    |   130 -
 .../model/BACnetAccessPassbackModeTagged.go        |   197 -
 .../readwrite/model/BACnetAccessUserType.go        |   138 -
 .../readwrite/model/BACnetAccessUserTypeTagged.go  |   246 -
 .../model/BACnetAccessZoneOccupancyState.go        |   170 -
 .../model/BACnetAccessZoneOccupancyStateTagged.go  |   246 -
 .../bacnetip/readwrite/model/BACnetAction.go       |   122 -
 .../readwrite/model/BACnetActionCommand.go         |   511 -
 .../bacnetip/readwrite/model/BACnetActionList.go   |   245 -
 .../bacnetip/readwrite/model/BACnetActionTagged.go |   197 -
 .../bacnetip/readwrite/model/BACnetAddress.go      |   196 -
 .../readwrite/model/BACnetApplicationTag.go        |   282 -
 .../model/BACnetApplicationTagBitString.go         |   199 -
 .../readwrite/model/BACnetApplicationTagBoolean.go |   225 -
 .../model/BACnetApplicationTagCharacterString.go   |   225 -
 .../readwrite/model/BACnetApplicationTagDate.go    |   199 -
 .../readwrite/model/BACnetApplicationTagDouble.go  |   225 -
 .../model/BACnetApplicationTagEnumerated.go        |   225 -
 .../readwrite/model/BACnetApplicationTagNull.go    |   151 -
 .../model/BACnetApplicationTagObjectIdentifier.go  |   242 -
 .../model/BACnetApplicationTagOctetString.go       |   225 -
 .../readwrite/model/BACnetApplicationTagReal.go    |   225 -
 .../model/BACnetApplicationTagSignedInteger.go     |   225 -
 .../readwrite/model/BACnetApplicationTagTime.go    |   199 -
 .../model/BACnetApplicationTagUnsignedInteger.go   |   225 -
 .../model/BACnetAuthenticationFactorType.go        |   306 -
 .../model/BACnetAuthenticationFactorTypeTagged.go  |   197 -
 .../readwrite/model/BACnetAuthenticationStatus.go  |   162 -
 .../model/BACnetAuthenticationStatusTagged.go      |   197 -
 .../model/BACnetAuthorizationExemption.go          |   170 -
 .../model/BACnetAuthorizationExemptionTagged.go    |   246 -
 .../readwrite/model/BACnetAuthorizationMode.go     |   162 -
 .../model/BACnetAuthorizationModeTagged.go         |   246 -
 .../bacnetip/readwrite/model/BACnetBackupState.go  |   162 -
 .../readwrite/model/BACnetBackupStateTagged.go     |   197 -
 .../readwrite/model/BACnetBinaryLightingPV.go      |   162 -
 .../model/BACnetBinaryLightingPVTagged.go          |   246 -
 .../bacnetip/readwrite/model/BACnetBinaryPV.go     |   122 -
 .../readwrite/model/BACnetBinaryPVTagged.go        |   197 -
 .../readwrite/model/BACnetCharacterEncoding.go     |   154 -
 .../bacnetip/readwrite/model/BACnetClosingTag.go   |   178 -
 .../model/BACnetConfirmedServiceChoice.go          |   362 -
 .../model/BACnetConfirmedServiceRequest.go         |   261 -
 ...ACnetConfirmedServiceRequestAcknowledgeAlarm.go |   390 -
 .../BACnetConfirmedServiceRequestAddListElement.go |   345 -
 .../BACnetConfirmedServiceRequestAtomicReadFile.go |   242 -
 ...tConfirmedServiceRequestAtomicReadFileRecord.go |   238 -
 ...tConfirmedServiceRequestAtomicReadFileStream.go |   238 -
 ...edServiceRequestAtomicReadFileStreamOrRecord.go |   288 -
 ...BACnetConfirmedServiceRequestAtomicWriteFile.go |   382 -
 .../BACnetConfirmedServiceRequestAuthenticate.go   |   162 -
 ...firmedServiceRequestConfirmedCOVNotification.go |   353 -
 ...rviceRequestConfirmedCOVNotificationMultiple.go |   368 -
 ...rmedServiceRequestConfirmedEventNotification.go |   706 -
 ...firmedServiceRequestConfirmedPrivateTransfer.go |   294 -
 ...tConfirmedServiceRequestConfirmedTextMessage.go |   162 -
 ...ACnetConfirmedServiceRequestConfirmedUnknown.go |   197 -
 .../BACnetConfirmedServiceRequestCreateObject.go   |   257 -
 ...medServiceRequestCreateObjectObjectSpecifier.go |   374 -
 .../BACnetConfirmedServiceRequestDeleteObject.go   |   205 -
 ...rmedServiceRequestDeviceCommunicationControl.go |   308 -
 ...tConfirmedServiceRequestGetEnrollmentSummary.go |   162 -
 ...etConfirmedServiceRequestGetEventInformation.go |   220 -
 ...etConfirmedServiceRequestLifeSafetyOperation.go |   162 -
 .../BACnetConfirmedServiceRequestReadProperty.go   |   294 -
 ...nfirmedServiceRequestReadPropertyConditional.go |   162 -
 ...tConfirmedServiceRequestReadPropertyMultiple.go |   221 -
 .../BACnetConfirmedServiceRequestReadRange.go      |   345 -
 .../BACnetConfirmedServiceRequestReadRangeRange.go |   290 -
 ...firmedServiceRequestReadRangeRangeByPosition.go |   238 -
 ...ServiceRequestReadRangeRangeBySequenceNumber.go |   238 -
 ...tConfirmedServiceRequestReadRangeRangeByTime.go |   238 -
 ...netConfirmedServiceRequestReinitializeDevice.go |   257 -
 ...erviceRequestReinitializeDeviceEnableDisable.go |   130 -
 ...RequestReinitializeDeviceEnableDisableTagged.go |   197 -
 ...ReinitializeDeviceReinitializedStateOfDevice.go |   178 -
 ...ializeDeviceReinitializedStateOfDeviceTagged.go |   197 -
 ...CnetConfirmedServiceRequestRemoveListElement.go |   345 -
 .../BACnetConfirmedServiceRequestRequestKey.go     |   162 -
 .../BACnetConfirmedServiceRequestSubscribeCOV.go   |   345 -
 ...tConfirmedServiceRequestSubscribeCOVProperty.go |   433 -
 ...edServiceRequestSubscribeCOVPropertyMultiple.go |   396 -
 ...yMultipleListOfCovSubscriptionSpecifications.go |   280 -
 ...tipleListOfCovSubscriptionSpecificationsList.go |   248 -
 ...ListOfCovSubscriptionSpecificationsReference.go |   245 -
 .../model/BACnetConfirmedServiceRequestVTClose.go  |   162 -
 .../model/BACnetConfirmedServiceRequestVTData.go   |   162 -
 .../model/BACnetConfirmedServiceRequestVTOpen.go   |   162 -
 .../BACnetConfirmedServiceRequestWriteProperty.go  |   382 -
 ...ConfirmedServiceRequestWritePropertyMultiple.go |   221 -
 .../readwrite/model/BACnetConstructedData.go       |   276 -
 .../model/BACnetConstructedDataAcceptedModes.go    |   226 -
 .../readwrite/model/BACnetConstructedDataAction.go |   226 -
 .../model/BACnetConstructedDataElement.go          |   403 -
 .../model/BACnetConstructedDataEventTimestamps.go  |   285 -
 .../BACnetConstructedDataLifeSafetyAlarmValues.go  |   226 -
 ...netConstructedDataLifeSafetyPointAlarmValues.go |   226 -
 ...netConstructedDataLifeSafetyPointFaultValues.go |   226 -
 ...onstructedDataListOfObjectPropertyReferences.go |   226 -
 .../model/BACnetConstructedDataLoopAction.go       |   211 -
 .../model/BACnetConstructedDataMemberOf.go         |   226 -
 .../model/BACnetConstructedDataReliability.go      |   211 -
 .../model/BACnetConstructedDataSubordinateList.go  |   226 -
 .../model/BACnetConstructedDataUnspecified.go      |   226 -
 .../model/BACnetConstructedDataZoneMembers.go      |   226 -
 .../bacnetip/readwrite/model/BACnetContextTag.go   |   299 -
 .../readwrite/model/BACnetContextTagBitString.go   |   206 -
 .../readwrite/model/BACnetContextTagBoolean.go     |   263 -
 .../model/BACnetContextTagCharacterString.go       |   232 -
 .../readwrite/model/BACnetContextTagDate.go        |   206 -
 .../readwrite/model/BACnetContextTagDouble.go      |   232 -
 .../readwrite/model/BACnetContextTagEmpty.go       |   158 -
 .../readwrite/model/BACnetContextTagEnumerated.go  |   232 -
 .../readwrite/model/BACnetContextTagNull.go        |   163 -
 .../model/BACnetContextTagObjectIdentifier.go      |   249 -
 .../readwrite/model/BACnetContextTagOctetString.go |   232 -
 .../readwrite/model/BACnetContextTagReal.go        |   232 -
 .../model/BACnetContextTagSignedInteger.go         |   232 -
 .../readwrite/model/BACnetContextTagTime.go        |   206 -
 .../readwrite/model/BACnetContextTagUnknown.go     |   199 -
 .../model/BACnetContextTagUnsignedInteger.go       |   232 -
 .../bacnetip/readwrite/model/BACnetDataType.go     |   218 -
 .../bacnetip/readwrite/model/BACnetDateTime.go     |   195 -
 .../readwrite/model/BACnetDateTimeEnclosed.go      |   233 -
 .../model/BACnetDeviceObjectPropertyReference.go   |   294 -
 .../BACnetDeviceObjectPropertyReferenceEnclosed.go |   233 -
 .../readwrite/model/BACnetDeviceObjectReference.go |   210 -
 .../bacnetip/readwrite/model/BACnetDeviceState.go  |   169 -
 .../bacnetip/readwrite/model/BACnetDeviceStatus.go |   162 -
 .../readwrite/model/BACnetDeviceStatusTagged.go    |   246 -
 .../readwrite/model/BACnetDoorAlarmState.go        |   186 -
 .../readwrite/model/BACnetDoorAlarmStateTagged.go  |   246 -
 .../readwrite/model/BACnetDoorSecuredStatus.go     |   130 -
 .../model/BACnetDoorSecuredStatusTagged.go         |   197 -
 .../bacnetip/readwrite/model/BACnetDoorStatus.go   |   194 -
 .../readwrite/model/BACnetDoorStatusTagged.go      |   246 -
 .../bacnetip/readwrite/model/BACnetDoorValue.go    |   138 -
 .../readwrite/model/BACnetDoorValueTagged.go       |   197 -
 .../readwrite/model/BACnetEngineeringUnits.go      |  2122 --
 .../model/BACnetEngineeringUnitsTagged.go          |   246 -
 .../plc4go/bacnetip/readwrite/model/BACnetError.go |   181 -
 .../bacnetip/readwrite/model/BACnetErrorGeneral.go |   201 -
 .../readwrite/model/BACnetEscalatorFault.go        |   186 -
 .../readwrite/model/BACnetEscalatorFaultTagged.go  |   246 -
 .../readwrite/model/BACnetEscalatorMode.go         |   162 -
 .../readwrite/model/BACnetEscalatorModeTagged.go   |   246 -
 .../model/BACnetEscalatorOperationDirection.go     |   162 -
 .../BACnetEscalatorOperationDirectionTagged.go     |   246 -
 .../readwrite/model/BACnetEventProrities.go        |   303 -
 .../bacnetip/readwrite/model/BACnetEventState.go   |   162 -
 .../readwrite/model/BACnetEventStateTagged.go      |   246 -
 .../readwrite/model/BACnetEventSummariesList.go    |   248 -
 .../bacnetip/readwrite/model/BACnetEventSummary.go |   370 -
 .../readwrite/model/BACnetEventTimestamps.go       |   303 -
 .../readwrite/model/BACnetEventTransitionBits.go   |   223 -
 .../bacnetip/readwrite/model/BACnetEventType.go    |   274 -
 .../readwrite/model/BACnetEventTypeTagged.go       |   246 -
 .../bacnetip/readwrite/model/BACnetFaultType.go    |   170 -
 .../readwrite/model/BACnetFaultTypeTagged.go       |   197 -
 .../readwrite/model/BACnetFileAccessMethod.go      |   122 -
 .../model/BACnetFileAccessMethodTagged.go          |   197 -
 .../bacnetip/readwrite/model/BACnetIPMode.go       |   130 -
 .../bacnetip/readwrite/model/BACnetIPModeTagged.go |   197 -
 .../readwrite/model/BACnetLifeSafetyMode.go        |   234 -
 .../readwrite/model/BACnetLifeSafetyModeTagged.go  |   246 -
 .../readwrite/model/BACnetLifeSafetyOperation.go   |   194 -
 .../model/BACnetLifeSafetyOperationTagged.go       |   246 -
 .../readwrite/model/BACnetLifeSafetyState.go       |   306 -
 .../readwrite/model/BACnetLifeSafetyStateTagged.go |   246 -
 .../readwrite/model/BACnetLiftCarDirection.go      |   162 -
 .../model/BACnetLiftCarDirectionTagged.go          |   246 -
 .../readwrite/model/BACnetLiftCarDoorCommand.go    |   130 -
 .../model/BACnetLiftCarDoorCommandTagged.go        |   197 -
 .../readwrite/model/BACnetLiftCarDriveStatus.go    |   194 -
 .../model/BACnetLiftCarDriveStatusTagged.go        |   246 -
 .../bacnetip/readwrite/model/BACnetLiftCarMode.go  |   226 -
 .../readwrite/model/BACnetLiftCarModeTagged.go     |   246 -
 .../bacnetip/readwrite/model/BACnetLiftFault.go    |   250 -
 .../readwrite/model/BACnetLiftFaultTagged.go       |   246 -
 .../readwrite/model/BACnetLiftGroupMode.go         |   162 -
 .../readwrite/model/BACnetLiftGroupModeTagged.go   |   197 -
 .../readwrite/model/BACnetLightingInProgress.go    |   146 -
 .../model/BACnetLightingInProgressTagged.go        |   197 -
 .../readwrite/model/BACnetLightingOperation.go     |   202 -
 .../model/BACnetLightingOperationTagged.go         |   246 -
 .../readwrite/model/BACnetLightingTransition.go    |   138 -
 .../model/BACnetLightingTransitionTagged.go        |   246 -
 .../bacnetip/readwrite/model/BACnetLockStatus.go   |   146 -
 .../readwrite/model/BACnetLockStatusTagged.go      |   197 -
 .../bacnetip/readwrite/model/BACnetLoggingType.go  |   138 -
 .../readwrite/model/BACnetLoggingTypeTagged.go     |   246 -
 .../bacnetip/readwrite/model/BACnetMaintenance.go  |   146 -
 .../readwrite/model/BACnetMaintenanceTagged.go     |   246 -
 .../readwrite/model/BACnetNetworkNumberQuality.go  |   138 -
 .../model/BACnetNetworkNumberQualityTagged.go      |   197 -
 .../readwrite/model/BACnetNetworkPortCommand.go    |   178 -
 .../model/BACnetNetworkPortCommandTagged.go        |   246 -
 .../bacnetip/readwrite/model/BACnetNetworkType.go  |   202 -
 .../readwrite/model/BACnetNetworkTypeTagged.go     |   246 -
 .../bacnetip/readwrite/model/BACnetNodeType.go     |   282 -
 .../readwrite/model/BACnetNodeTypeTagged.go        |   197 -
 .../model/BACnetNotificationParameters.go          |   310 -
 .../BACnetNotificationParametersBufferReady.go     |   353 -
 ...ACnetNotificationParametersChangeOfBitString.go |   316 -
 .../BACnetNotificationParametersChangeOfState.go   |   316 -
 .../BACnetNotificationParametersChangeOfValue.go   |   316 -
 ...tNotificationParametersChangeOfValueNewValue.go |   291 -
 ...onParametersChangeOfValueNewValueChangedBits.go |   204 -
 ...nParametersChangeOfValueNewValueChangedValue.go |   204 -
 .../BACnetNotificationParametersCommandFailure.go  |   353 -
 ...BACnetNotificationParametersComplexEventType.go |   205 -
 .../model/BACnetNotificationParametersExtended.go  |   353 -
 ...CnetNotificationParametersExtendedParameters.go |  1044 -
 .../BACnetNotificationParametersFloatingLimit.go   |   390 -
 .../BACnetNotificationParametersOutOfRange.go      |   390 -
 .../model/BACnetNotificationParametersUnmapped.go  |   162 -
 .../BACnetNotificationParametersUnsignedRange.go   |   353 -
 .../bacnetip/readwrite/model/BACnetNotifyType.go   |   130 -
 .../readwrite/model/BACnetNotifyTypeTagged.go      |   197 -
 .../model/BACnetObjectPropertyReference.go         |   245 -
 .../model/BACnetObjectPropertyReferenceEnclosed.go |   233 -
 .../bacnetip/readwrite/model/BACnetObjectType.go   |   594 -
 .../readwrite/model/BACnetObjectTypeTagged.go      |   246 -
 .../bacnetip/readwrite/model/BACnetOpeningTag.go   |   178 -
 .../bacnetip/readwrite/model/BACnetPolarity.go     |   122 -
 .../readwrite/model/BACnetPolarityTagged.go        |   197 -
 .../bacnetip/readwrite/model/BACnetProgramError.go |   154 -
 .../readwrite/model/BACnetProgramErrorTagged.go    |   246 -
 .../readwrite/model/BACnetProgramRequest.go        |   154 -
 .../readwrite/model/BACnetProgramRequestTagged.go  |   197 -
 .../bacnetip/readwrite/model/BACnetProgramState.go |   154 -
 .../readwrite/model/BACnetProgramStateTagged.go    |   197 -
 .../readwrite/model/BACnetPropertyIdentifier.go    |  3770 ---
 .../model/BACnetPropertyIdentifierTagged.go        |   246 -
 .../readwrite/model/BACnetPropertyReference.go     |   210 -
 .../model/BACnetPropertyReferenceEnclosed.go       |   233 -
 .../model/BACnetPropertyStateActionUnmapped.go     |   161 -
 .../readwrite/model/BACnetPropertyStates.go        |   299 -
 .../readwrite/model/BACnetPropertyStatesAction.go  |   204 -
 .../model/BACnetPropertyStatesBinaryValue.go       |   204 -
 .../readwrite/model/BACnetPropertyStatesBoolean.go |   204 -
 .../model/BACnetPropertyStatesNetworkType.go       |   204 -
 .../model/BACnetPropertyStatesReliability.go       |   204 -
 .../readwrite/model/BACnetPropertyValue.go         |   311 -
 .../readwrite/model/BACnetPropertyValues.go        |   249 -
 .../model/BACnetPropertyWriteDefinition.go         |   311 -
 .../readwrite/model/BACnetProtocolLevel.go         |   138 -
 .../readwrite/model/BACnetProtocolLevelTagged.go   |   197 -
 .../readwrite/model/BACnetReadAccessProperty.go    |   262 -
 .../model/BACnetReadAccessPropertyReadResult.go    |   288 -
 .../readwrite/model/BACnetReadAccessResult.go      |   210 -
 .../model/BACnetReadAccessResultListOfResults.go   |   249 -
 .../model/BACnetReadAccessSpecification.go         |   280 -
 .../bacnetip/readwrite/model/BACnetRejectReason.go |   194 -
 .../readwrite/model/BACnetRejectReasonTagged.go    |   200 -
 .../bacnetip/readwrite/model/BACnetRelationship.go |   354 -
 .../readwrite/model/BACnetRelationshipTagged.go    |   246 -
 .../bacnetip/readwrite/model/BACnetReliability.go  |   306 -
 .../readwrite/model/BACnetReliabilityTagged.go     |   246 -
 .../readwrite/model/BACnetRestartReason.go         |   186 -
 .../readwrite/model/BACnetRestartReasonTagged.go   |   246 -
 .../bacnetip/readwrite/model/BACnetResultFlags.go  |   223 -
 .../readwrite/model/BACnetSecurityLevel.go         |   154 -
 .../readwrite/model/BACnetSecurityLevelTagged.go   |   197 -
 .../readwrite/model/BACnetSecurityPolicy.go        |   138 -
 .../readwrite/model/BACnetSecurityPolicyTagged.go  |   197 -
 .../bacnetip/readwrite/model/BACnetSegmentation.go |   138 -
 .../readwrite/model/BACnetSegmentationTagged.go    |   197 -
 .../bacnetip/readwrite/model/BACnetServiceAck.go   |   259 -
 .../model/BACnetServiceAckAcknowledgeAlarm.go      |   161 -
 .../model/BACnetServiceAckAddListElement.go        |   161 -
 .../model/BACnetServiceAckAtomicReadFile.go        |   241 -
 .../model/BACnetServiceAckAtomicReadFileRecord.go  |   290 -
 .../model/BACnetServiceAckAtomicReadFileStream.go  |   238 -
 ...BACnetServiceAckAtomicReadFileStreamOrRecord.go |   288 -
 .../model/BACnetServiceAckAtomicWriteFile.go       |   204 -
 .../model/BACnetServiceAckAuthenticate.go          |   161 -
 .../BACnetServiceAckConfirmedCovNotification.go    |   161 -
 ...etServiceAckConfirmedCovNotificationMultiple.go |   162 -
 .../BACnetServiceAckConfirmedEventNotification.go  |   161 -
 .../BACnetServiceAckConfirmedPrivateTransfer.go    |   293 -
 .../model/BACnetServiceAckConfirmedTextMessage.go  |   161 -
 .../model/BACnetServiceAckCreateObject.go          |   161 -
 .../BACnetServiceAckDeviceCommunicationControl.go  |   161 -
 .../model/BACnetServiceAckGetAlarmSummary.go       |   161 -
 .../model/BACnetServiceAckGetEnrollmentSummary.go  |   161 -
 .../model/BACnetServiceAckGetEventInformation.go   |   241 -
 .../model/BACnetServiceAckLifeSafetyOperation.go   |   161 -
 .../model/BACnetServiceAckReadProperty.go          |   344 -
 .../BACnetServiceAckReadPropertyConditional.go     |   161 -
 .../model/BACnetServiceAckReadPropertyMultiple.go  |   220 -
 .../readwrite/model/BACnetServiceAckReadRange.go   |   469 -
 .../model/BACnetServiceAckReinitializeDevice.go    |   161 -
 .../model/BACnetServiceAckRemoveListElement.go     |   161 -
 .../readwrite/model/BACnetServiceAckRequestKey.go  |   161 -
 .../model/BACnetServiceAckSubscribeCov.go          |   161 -
 .../model/BACnetServiceAckSubscribeCovProperty.go  |   161 -
 ...BACnetServiceAckSubscribeCovPropertyMultiple.go |   161 -
 .../readwrite/model/BACnetServiceAckVTClose.go     |   161 -
 .../readwrite/model/BACnetServiceAckVTData.go      |   161 -
 .../readwrite/model/BACnetServiceAckVTOpen.go      |   161 -
 .../model/BACnetServiceAckWriteProperty.go         |   161 -
 .../model/BACnetServiceAckWritePropertyMultiple.go |   161 -
 .../bacnetip/readwrite/model/BACnetShedState.go    |   138 -
 .../readwrite/model/BACnetShedStateTagged.go       |   197 -
 .../readwrite/model/BACnetSilencedState.go         |   146 -
 .../readwrite/model/BACnetSilencedStateTagged.go   |   246 -
 .../bacnetip/readwrite/model/BACnetStatusFlags.go  |   240 -
 .../bacnetip/readwrite/model/BACnetTagHeader.go    |   478 -
 .../readwrite/model/BACnetTagPayloadBitString.go   |   246 -
 .../readwrite/model/BACnetTagPayloadBoolean.go     |   179 -
 .../model/BACnetTagPayloadCharacterString.go       |   213 -
 .../readwrite/model/BACnetTagPayloadDate.go        |   417 -
 .../readwrite/model/BACnetTagPayloadDouble.go      |   149 -
 .../readwrite/model/BACnetTagPayloadEnumerated.go  |   181 -
 .../model/BACnetTagPayloadObjectIdentifier.go      |   221 -
 .../readwrite/model/BACnetTagPayloadOctetString.go |   178 -
 .../readwrite/model/BACnetTagPayloadReal.go        |   149 -
 .../model/BACnetTagPayloadSignedInteger.go         |   719 -
 .../readwrite/model/BACnetTagPayloadTime.go        |   315 -
 .../model/BACnetTagPayloadUnsignedInteger.go       |   719 -
 .../bacnetip/readwrite/model/BACnetTimeStamp.go    |   220 -
 .../readwrite/model/BACnetTimeStampDateTime.go     |   199 -
 .../readwrite/model/BACnetTimeStampEnclosed.go     |   233 -
 .../readwrite/model/BACnetTimeStampSequence.go     |   199 -
 .../readwrite/model/BACnetTimeStampTime.go         |   199 -
 .../readwrite/model/BACnetTimeStampsEnclosed.go    |   248 -
 .../bacnetip/readwrite/model/BACnetTimerState.go   |   130 -
 .../readwrite/model/BACnetTimerStateTagged.go      |   197 -
 .../readwrite/model/BACnetTimerTransition.go       |   170 -
 .../readwrite/model/BACnetTimerTransitionTagged.go |   197 -
 .../model/BACnetUnconfirmedServiceChoice.go        |   202 -
 .../model/BACnetUnconfirmedServiceChoiceTagged.go  |   197 -
 .../model/BACnetUnconfirmedServiceRequest.go       |   223 -
 .../model/BACnetUnconfirmedServiceRequestIAm.go    |   316 -
 .../model/BACnetUnconfirmedServiceRequestIHave.go  |   279 -
 ...UnconfirmedServiceRequestTimeSynchronization.go |   242 -
 ...onfirmedServiceRequestUTCTimeSynchronization.go |   242 -
 ...rmedServiceRequestUnconfirmedCOVNotification.go |   353 -
 ...iceRequestUnconfirmedCOVNotificationMultiple.go |   368 -
 ...edServiceRequestUnconfirmedEventNotification.go |   706 -
 ...rmedServiceRequestUnconfirmedPrivateTransfer.go |   294 -
 ...onfirmedServiceRequestUnconfirmedTextMessage.go |   162 -
 ...tUnconfirmedServiceRequestUnconfirmedUnknown.go |   197 -
 .../model/BACnetUnconfirmedServiceRequestWhoHas.go |   373 -
 .../model/BACnetUnconfirmedServiceRequestWhoIs.go  |   271 -
 .../BACnetUnconfirmedServiceRequestWriteGroup.go   |   162 -
 .../bacnetip/readwrite/model/BACnetVTClass.go      |   170 -
 .../readwrite/model/BACnetVTClassTagged.go         |   246 -
 .../bacnetip/readwrite/model/BACnetVendorId.go     | 21775 ------------------
 .../model/BACnetWriteAccessSpecification.go        |   280 -
 .../bacnetip/readwrite/model/BACnetWriteStatus.go  |   138 -
 .../readwrite/model/BACnetWriteStatusTagged.go     |   197 -
 .../plc4go/bacnetip/readwrite/model/BVLC.go        |   286 -
 .../model/BVLCBroadcastDistributionTableEntry.go   |   243 -
 .../model/BVLCDeleteForeignDeviceTableEntry.go     |   239 -
 .../model/BVLCDistributeBroadcastToNetwork.go      |   204 -
 .../readwrite/model/BVLCForeignDeviceTableEntry.go |   244 -
 .../bacnetip/readwrite/model/BVLCForwardedNPDU.go  |   279 -
 .../readwrite/model/BVLCOriginalBroadcastNPDU.go   |   204 -
 .../readwrite/model/BVLCOriginalUnicastNPDU.go     |   204 -
 .../model/BVLCReadBroadcastDistributionTable.go    |   153 -
 .../model/BVLCReadBroadcastDistributionTableAck.go |   220 -
 .../readwrite/model/BVLCReadForeignDeviceTable.go  |   153 -
 .../model/BVLCReadForeignDeviceTableAck.go         |   220 -
 .../readwrite/model/BVLCRegisterForeignDevice.go   |   190 -
 .../plc4go/bacnetip/readwrite/model/BVLCResult.go  |   201 -
 .../bacnetip/readwrite/model/BVLCResultCode.go     |   162 -
 .../readwrite/model/BVLCResultCodeTagged.go        |   197 -
 .../bacnetip/readwrite/model/BVLCSecureBVLL.go     |   196 -
 .../model/BVLCWriteBroadcastDistributionTable.go   |   220 -
 .../bacnetip/readwrite/model/ChangeListAddError.go |   238 -
 .../readwrite/model/ChangeListRemoveError.go       |   238 -
 .../model/ConfirmedPrivateTransferError.go         |   327 -
 .../bacnetip/readwrite/model/CreateObjectError.go  |   238 -
 .../plc4go/bacnetip/readwrite/model/Error.go       |   195 -
 .../plc4go/bacnetip/readwrite/model/ErrorClass.go  |   178 -
 .../bacnetip/readwrite/model/ErrorClassTagged.go   |   246 -
 .../plc4go/bacnetip/readwrite/model/ErrorCode.go   |  1146 -
 .../bacnetip/readwrite/model/ErrorCodeTagged.go    |   246 -
 .../bacnetip/readwrite/model/ErrorEnclosed.go      |   233 -
 .../readwrite/model/ListOfCovNotifications.go      |   280 -
 .../readwrite/model/ListOfCovNotificationsList.go  |   248 -
 .../readwrite/model/ListOfCovNotificationsValue.go |   297 -
 .../readwrite/model/MaxApduLengthAccepted.go       |   234 -
 .../readwrite/model/MaxApduLengthAcceptedTagged.go |   197 -
 .../readwrite/model/MaxSegmentsAccepted.go         |   170 -
 .../readwrite/model/MaxSegmentsAcceptedTagged.go   |   197 -
 .../plc4go/bacnetip/readwrite/model/NLM.go         |   246 -
 .../model/NLMDisconnectConnectionToNetwork.go      |   195 -
 .../model/NLMEstablishConnectionToNetwork.go       |   221 -
 .../readwrite/model/NLMIAmRouterToNetwork.go       |   220 -
 .../readwrite/model/NLMICouldBeRouterToNetwork.go  |   221 -
 .../readwrite/model/NLMInitalizeRoutingTable.go    |   247 -
 .../readwrite/model/NLMInitalizeRoutingTableAck.go |   247 -
 .../model/NLMInitalizeRoutingTablePortMapping.go   |   224 -
 .../readwrite/model/NLMRejectRouterToNetwork.go    |   232 -
 .../model/NLMRejectRouterToNetworkRejectReason.go  |   162 -
 .../readwrite/model/NLMRouterAvailableToNetwork.go |   220 -
 .../readwrite/model/NLMRouterBusyToNetwork.go      |   220 -
 .../readwrite/model/NLMWhoIsRouterToNetwork.go     |   220 -
 .../plc4go/bacnetip/readwrite/model/NPDU.go        |   647 -
 .../plc4go/bacnetip/readwrite/model/NPDUControl.go |   307 -
 .../readwrite/model/NPDUNetworkPriority.go         |   138 -
 .../readwrite/model/NPDUNetworkPriorityTagged.go   |   197 -
 .../bacnetip/readwrite/model/StaticHelper.go       |   618 -
 .../model/SubscribeCOVPropertyMultipleError.go     |   238 -
 ...PropertyMultipleErrorFirstFailedSubscription.go |   303 -
 .../plc4go/bacnetip/readwrite/model/TagClass.go    |   122 -
 .../bacnetip/readwrite/model/VTCloseError.go       |   253 -
 .../VTCloseErrorListOfVTSessionIdentifiers.go      |   248 -
 .../readwrite/model/WritePropertyMultipleError.go  |   238 -
 .../internal/plc4go/cbus/readwrite/ParserHelper.go |   120 -
 .../plc4go/cbus/readwrite/XmlParserHelper.go       |   118 -
 .../internal/plc4go/cbus/readwrite/model/Alpha.go  |   149 -
 .../plc4go/cbus/readwrite/model/Application.go     |   143 -
 .../plc4go/cbus/readwrite/model/ApplicationId.go   |   266 -
 .../cbus/readwrite/model/ApplicationIdContainer.go |  4239 ----
 .../plc4go/cbus/readwrite/model/Attribute.go       |   340 -
 .../plc4go/cbus/readwrite/model/BridgeAddress.go   |   149 -
 .../plc4go/cbus/readwrite/model/BridgeCount.go     |   149 -
 .../plc4go/cbus/readwrite/model/CALCommandType.go  |   158 -
 .../readwrite/model/CALCommandTypeContainer.go     |  1697 --
 .../plc4go/cbus/readwrite/model/CALData.go         |   250 -
 .../readwrite/model/CALDataReplyAcknowledge.go     |   214 -
 .../cbus/readwrite/model/CALDataReplyReply.go      |   217 -
 .../cbus/readwrite/model/CALDataReplyStatus.go     |   254 -
 .../readwrite/model/CALDataReplyStatusExtended.go  |   280 -
 .../readwrite/model/CALDataRequestGetStatus.go     |   214 -
 .../cbus/readwrite/model/CALDataRequestIdentify.go |   199 -
 .../cbus/readwrite/model/CALDataRequestRecall.go   |   214 -
 .../cbus/readwrite/model/CALDataRequestReset.go    |   151 -
 .../plc4go/cbus/readwrite/model/CALReply.go        |   286 -
 .../plc4go/cbus/readwrite/model/CALReplyLong.go    |   471 -
 .../plc4go/cbus/readwrite/model/CALReplyReply.go   |   199 -
 .../plc4go/cbus/readwrite/model/CALReplyShort.go   |   152 -
 .../plc4go/cbus/readwrite/model/CBusCommand.go     |   278 -
 .../model/CBusCommandPointToMultiPoint.go          |   202 -
 .../readwrite/model/CBusCommandPointToPoint.go     |   202 -
 .../model/CBusCommandPointToPointToMultiPoint.go   |   202 -
 .../CBusCommandPointToPointToMultiPointNormal.go   |   397 -
 .../CBusCommandPointToPointToMultiPointStatus.go   |   386 -
 .../plc4go/cbus/readwrite/model/CBusHeader.go      |   246 -
 .../plc4go/cbus/readwrite/model/CBusOptions.go     |   317 -
 .../model/CBusPointToMultiPointCommand.go          |   196 -
 .../model/CBusPointToMultiPointCommandNormal.go    |   421 -
 .../model/CBusPointToMultiPointCommandStatus.go    |   409 -
 .../readwrite/model/CBusPointToPointCommand.go     |   411 -
 .../model/CBusPointToPointCommandDirect.go         |   232 -
 .../model/CBusPointToPointCommandIndirect.go       |   280 -
 .../model/CBusPointToPointToMultipointCommand.go   |   266 -
 .../plc4go/cbus/readwrite/model/ChannelStatus.go   |   130 -
 .../plc4go/cbus/readwrite/model/Checksum.go        |   149 -
 .../plc4go/cbus/readwrite/model/CommandHeader.go   |   149 -
 .../plc4go/cbus/readwrite/model/Confirmation.go    |   236 -
 .../cbus/readwrite/model/ConfirmationReply.go      |   199 -
 .../cbus/readwrite/model/ConfirmationSuccessful.go |   155 -
 .../cbus/readwrite/model/DestinationAddressType.go |   130 -
 .../plc4go/cbus/readwrite/model/ExclamationMark.go |   114 -
 .../cbus/readwrite/model/ExclamationMarkReply.go   |   199 -
 .../readwrite/model/ExtendedFormatStatusReply.go   |   397 -
 .../cbus/readwrite/model/ExtendedStatusHeader.go   |   175 -
 .../plc4go/cbus/readwrite/model/GAVState.go        |   138 -
 .../cbus/readwrite/model/IdentifyReplyCommand.go   |   201 -
 .../IdentifyReplyCommandCurrentSenseLevels.go      |   153 -
 .../model/IdentifyReplyCommandDSIStatus.go         |   523 -
 .../readwrite/model/IdentifyReplyCommandDelays.go  |   153 -
 ...dentifyReplyCommandExtendedDiagnosticSummary.go |   757 -
 .../model/IdentifyReplyCommandFirmwareSummary.go   |   242 -
 .../model/IdentifyReplyCommandFirmwareVersion.go   |   190 -
 .../IdentifyReplyCommandGAVPhysicalAddresses.go    |   193 -
 .../model/IdentifyReplyCommandGAVValuesCurrent.go  |   193 -
 .../model/IdentifyReplyCommandGAVValuesStored.go   |   193 -
 .../model/IdentifyReplyCommandLogicalAssignment.go |   153 -
 .../model/IdentifyReplyCommandManufacturer.go      |   190 -
 .../model/IdentifyReplyCommandMaximumLevels.go     |   153 -
 .../model/IdentifyReplyCommandMinimumLevels.go     |   153 -
 .../IdentifyReplyCommandNetworkTerminalLevels.go   |   153 -
 .../model/IdentifyReplyCommandNetworkVoltage.go    |   274 -
 .../model/IdentifyReplyCommandOutputUnitSummary.go |   153 -
 .../model/IdentifyReplyCommandTerminalLevels.go    |   153 -
 .../readwrite/model/IdentifyReplyCommandType.go    |   190 -
 .../cbus/readwrite/model/LightingCompatible.go     |   138 -
 .../plc4go/cbus/readwrite/model/MonitoredSAL.go    |   301 -
 .../model/MonitoredSALLongFormSmartMode.go         |   471 -
 .../cbus/readwrite/model/MonitoredSALReply.go      |   199 -
 .../model/MonitoredSALShortFormBasicMode.go        |   355 -
 .../plc4go/cbus/readwrite/model/NetworkNumber.go   |   149 -
 .../model/NetworkProtocolControlInformation.go     |   199 -
 .../plc4go/cbus/readwrite/model/NetworkRoute.go    |   210 -
 .../readwrite/model/NotTransmittedCorruption.go    |   155 -
 .../cbus/readwrite/model/NotTransmittedSyncLoss.go |   155 -
 .../model/NotTransmittedToManyReTransmissions.go   |   155 -
 .../cbus/readwrite/model/NotTransmittedTooLong.go  |   155 -
 .../plc4go/cbus/readwrite/model/ParameterChange.go |   220 -
 .../cbus/readwrite/model/ParameterChangeReply.go   |   199 -
 .../plc4go/cbus/readwrite/model/PowerUp.go         |   197 -
 .../plc4go/cbus/readwrite/model/PowerUpReply.go    |   199 -
 .../plc4go/cbus/readwrite/model/PriorityClass.go   |   138 -
 .../internal/plc4go/cbus/readwrite/model/Reply.go  |   201 -
 .../plc4go/cbus/readwrite/model/ReplyNetwork.go    |   245 -
 .../plc4go/cbus/readwrite/model/RouteType.go       |   208 -
 .../plc4go/cbus/readwrite/model/SALCommandType.go  |   138 -
 .../readwrite/model/SALCommandTypeContainer.go     |   352 -
 .../plc4go/cbus/readwrite/model/SALData.go         |   242 -
 .../plc4go/cbus/readwrite/model/SALDataOff.go      |   188 -
 .../plc4go/cbus/readwrite/model/SALDataOn.go       |   188 -
 .../cbus/readwrite/model/SALDataRampToLevel.go     |   214 -
 .../cbus/readwrite/model/SALDataTerminateRamp.go   |   188 -
 .../cbus/readwrite/model/SerialInterfaceAddress.go |   149 -
 .../readwrite/model/StandardFormatStatusReply.go   |   362 -
 .../plc4go/cbus/readwrite/model/StatusByte.go      |   265 -
 .../plc4go/cbus/readwrite/model/StatusCoding.go    |   138 -
 .../plc4go/cbus/readwrite/model/StatusHeader.go    |   175 -
 .../plc4go/cbus/readwrite/model/StatusRequest.go   |   193 -
 .../readwrite/model/StatusRequestBinaryState.go    |   239 -
 .../cbus/readwrite/model/StatusRequestLevel.go     |   270 -
 .../plc4go/cbus/readwrite/model/UnitAddress.go     |   149 -
 .../plc4go/cbus/readwrite/model/UnitStatus.go      |   130 -
 .../internal/plc4go/df1/readwrite/ParserHelper.go  |    41 -
 .../plc4go/df1/readwrite/XmlParserHelper.go        |    51 -
 .../plc4go/df1/readwrite/model/DF1Command.go       |   243 -
 .../plc4go/df1/readwrite/model/DF1Symbol.go        |   223 -
 .../df1/readwrite/model/DF1SymbolMessageFrame.go   |   341 -
 .../readwrite/model/DF1SymbolMessageFrameACK.go    |   153 -
 .../readwrite/model/DF1SymbolMessageFrameNAK.go    |   153 -
 .../readwrite/model/DF1UnprotectedReadRequest.go   |   219 -
 .../readwrite/model/DF1UnprotectedReadResponse.go  |   209 -
 .../plc4go/df1/readwrite/model/StaticHelper.go     |    84 -
 plc4go/internal/plc4go/eip/Connection.go           |   208 -
 plc4go/internal/plc4go/eip/Driver.go               |   110 -
 plc4go/internal/plc4go/eip/Field.go                |    99 -
 plc4go/internal/plc4go/eip/FieldHandler.go         |    56 -
 plc4go/internal/plc4go/eip/MessageCodec.go         |   102 -
 plc4go/internal/plc4go/eip/Reader.go               |   541 -
 plc4go/internal/plc4go/eip/ValueHandler.go         |    32 -
 plc4go/internal/plc4go/eip/Writer.go               |   361 -
 .../internal/plc4go/eip/readwrite/ParserHelper.go  |    57 -
 .../plc4go/eip/readwrite/XmlParserHelper.go        |    70 -
 .../plc4go/eip/readwrite/model/CIPDataTypeCode.go  |   224 -
 .../plc4go/eip/readwrite/model/CipExchange.go      |   261 -
 .../plc4go/eip/readwrite/model/CipRRData.go        |   260 -
 .../plc4go/eip/readwrite/model/CipReadRequest.go   |   248 -
 .../plc4go/eip/readwrite/model/CipReadResponse.go  |   311 -
 .../plc4go/eip/readwrite/model/CipService.go       |   198 -
 .../eip/readwrite/model/CipUnconnectedRequest.go   |   459 -
 .../plc4go/eip/readwrite/model/CipWriteRequest.go  |   314 -
 .../plc4go/eip/readwrite/model/CipWriteResponse.go |   245 -
 .../plc4go/eip/readwrite/model/EiPCommand.go       |   130 -
 .../eip/readwrite/model/EipConnectionRequest.go    |   218 -
 .../eip/readwrite/model/EipDisconnectRequest.go    |   158 -
 .../plc4go/eip/readwrite/model/EipPacket.go        |   333 -
 .../eip/readwrite/model/MultipleServiceRequest.go  |   262 -
 .../eip/readwrite/model/MultipleServiceResponse.go |   349 -
 .../plc4go/eip/readwrite/model/Services.go         |   249 -
 .../plc4go/firmata/readwrite/ParserHelper.go       |    55 -
 .../plc4go/firmata/readwrite/XmlParserHelper.go    |    56 -
 .../firmata/readwrite/model/FirmataCommand.go      |   194 -
 .../model/FirmataCommandProtocolVersion.go         |   219 -
 .../model/FirmataCommandSetDigitalPinValue.go      |   245 -
 .../readwrite/model/FirmataCommandSetPinMode.go    |   230 -
 .../firmata/readwrite/model/FirmataCommandSysex.go |   230 -
 .../readwrite/model/FirmataCommandSystemReset.go   |   156 -
 .../firmata/readwrite/model/FirmataMessage.go      |   194 -
 .../readwrite/model/FirmataMessageAnalogIO.go      |   242 -
 .../readwrite/model/FirmataMessageCommand.go       |   204 -
 .../readwrite/model/FirmataMessageDigitalIO.go     |   242 -
 .../model/FirmataMessageSubscribeAnalogPinValue.go |   245 -
 .../FirmataMessageSubscribeDigitalPinValue.go      |   245 -
 .../plc4go/firmata/readwrite/model/PinMode.go      |   202 -
 .../plc4go/firmata/readwrite/model/StaticHelper.go |    45 -
 .../plc4go/firmata/readwrite/model/SysexCommand.go |   213 -
 .../model/SysexCommandAnalogMappingQueryRequest.go |   157 -
 .../SysexCommandAnalogMappingQueryResponse.go      |   194 -
 .../model/SysexCommandAnalogMappingResponse.go     |   157 -
 .../readwrite/model/SysexCommandCapabilityQuery.go |   157 -
 .../model/SysexCommandCapabilityResponse.go        |   157 -
 .../readwrite/model/SysexCommandExtendedAnalog.go  |   157 -
 .../readwrite/model/SysexCommandExtendedId.go      |   217 -
 .../readwrite/model/SysexCommandPinStateQuery.go   |   194 -
 .../model/SysexCommandPinStateResponse.go          |   246 -
 .../model/SysexCommandReportFirmwareRequest.go     |   157 -
 .../model/SysexCommandReportFirmwareResponse.go    |   263 -
 .../model/SysexCommandSamplingInterval.go          |   157 -
 .../readwrite/model/SysexCommandStringData.go      |   157 -
 .../model/SysexCommandSysexNonRealtime.go          |   157 -
 .../readwrite/model/SysexCommandSysexRealtime.go   |   157 -
 plc4go/internal/plc4go/knxnetip/Browser.go         |   703 -
 plc4go/internal/plc4go/knxnetip/Connection.go      |   494 -
 .../knxnetip/ConnectionDriverSpecificOperations.go |   521 -
 .../internal/plc4go/knxnetip/ConnectionHelper.go   |   237 -
 .../knxnetip/ConnectionInternalOperations.go       |  1183 -
 plc4go/internal/plc4go/knxnetip/Discoverer.go      |   190 -
 plc4go/internal/plc4go/knxnetip/Driver.go          |    82 -
 plc4go/internal/plc4go/knxnetip/Field.go           |   468 -
 plc4go/internal/plc4go/knxnetip/FieldHandler.go    |   132 -
 plc4go/internal/plc4go/knxnetip/MessageCodec.go    |   140 -
 plc4go/internal/plc4go/knxnetip/Reader.go          |   351 -
 plc4go/internal/plc4go/knxnetip/Subscriber.go      |   178 -
 .../internal/plc4go/knxnetip/SubscriptionEvent.go  |    68 -
 plc4go/internal/plc4go/knxnetip/Utils.go           |   102 -
 plc4go/internal/plc4go/knxnetip/ValueDecoder.go    |    45 -
 plc4go/internal/plc4go/knxnetip/Writer.go          |    73 -
 .../plc4go/knxnetip/readwrite/ParserHelper.go      |   138 -
 .../plc4go/knxnetip/readwrite/XmlParserHelper.go   |   154 -
 .../plc4go/knxnetip/readwrite/model/AccessLevel.go |   223 -
 .../plc4go/knxnetip/readwrite/model/Apdu.go        |   246 -
 .../plc4go/knxnetip/readwrite/model/ApduControl.go |   189 -
 .../knxnetip/readwrite/model/ApduControlAck.go     |   153 -
 .../knxnetip/readwrite/model/ApduControlConnect.go |   153 -
 .../readwrite/model/ApduControlContainer.go        |   207 -
 .../readwrite/model/ApduControlDisconnect.go       |   153 -
 .../knxnetip/readwrite/model/ApduControlNack.go    |   153 -
 .../plc4go/knxnetip/readwrite/model/ApduData.go    |   216 -
 .../knxnetip/readwrite/model/ApduDataAdcRead.go    |   156 -
 .../readwrite/model/ApduDataAdcResponse.go         |   156 -
 .../knxnetip/readwrite/model/ApduDataContainer.go  |   207 -
 .../model/ApduDataDeviceDescriptorRead.go          |   193 -
 .../model/ApduDataDeviceDescriptorResponse.go      |   222 -
 .../plc4go/knxnetip/readwrite/model/ApduDataExt.go |   266 -
 .../readwrite/model/ApduDataExtAuthorizeRequest.go |   222 -
 .../model/ApduDataExtAuthorizeResponse.go          |   193 -
 .../model/ApduDataExtDomainAddressRead.go          |   156 -
 .../model/ApduDataExtDomainAddressResponse.go      |   156 -
 .../model/ApduDataExtDomainAddressSelectiveRead.go |   156 -
 .../ApduDataExtDomainAddressSerialNumberRead.go    |   156 -
 ...ApduDataExtDomainAddressSerialNumberResponse.go |   156 -
 .../ApduDataExtDomainAddressSerialNumberWrite.go   |   156 -
 .../model/ApduDataExtDomainAddressWrite.go         |   156 -
 .../model/ApduDataExtFileStreamInfoReport.go       |   156 -
 .../ApduDataExtGroupPropertyValueInfoReport.go     |   156 -
 .../model/ApduDataExtGroupPropertyValueRead.go     |   156 -
 .../model/ApduDataExtGroupPropertyValueResponse.go |   156 -
 .../model/ApduDataExtGroupPropertyValueWrite.go    |   156 -
 ...ApduDataExtIndividualAddressSerialNumberRead.go |   156 -
 ...DataExtIndividualAddressSerialNumberResponse.go |   156 -
 ...pduDataExtIndividualAddressSerialNumberWrite.go |   156 -
 .../readwrite/model/ApduDataExtKeyResponse.go      |   156 -
 .../readwrite/model/ApduDataExtKeyWrite.go         |   156 -
 .../readwrite/model/ApduDataExtLinkRead.go         |   156 -
 .../readwrite/model/ApduDataExtLinkResponse.go     |   156 -
 .../readwrite/model/ApduDataExtLinkWrite.go        |   156 -
 .../readwrite/model/ApduDataExtMemoryBitWrite.go   |   156 -
 .../model/ApduDataExtNetworkParameterRead.go       |   156 -
 .../model/ApduDataExtNetworkParameterResponse.go   |   156 -
 .../model/ApduDataExtNetworkParameterWrite.go      |   156 -
 .../model/ApduDataExtOpenRoutingTableRequest.go    |   156 -
 .../model/ApduDataExtPropertyDescriptionRead.go    |   245 -
 .../ApduDataExtPropertyDescriptionResponse.go      |   459 -
 .../model/ApduDataExtPropertyValueRead.go          |   271 -
 .../model/ApduDataExtPropertyValueResponse.go      |   300 -
 .../model/ApduDataExtPropertyValueWrite.go         |   300 -
 .../model/ApduDataExtReadRouterMemoryRequest.go    |   156 -
 .../model/ApduDataExtReadRouterMemoryResponse.go   |   156 -
 .../model/ApduDataExtReadRouterStatusRequest.go    |   156 -
 .../model/ApduDataExtReadRouterStatusResponse.go   |   156 -
 .../model/ApduDataExtReadRoutingTableRequest.go    |   156 -
 .../model/ApduDataExtReadRoutingTableResponse.go   |   156 -
 .../model/ApduDataExtWriteRouterMemoryRequest.go   |   156 -
 .../model/ApduDataExtWriteRouterStatusRequest.go   |   156 -
 .../model/ApduDataExtWriteRoutingTableRequest.go   |   156 -
 .../readwrite/model/ApduDataGroupValueRead.go      |   183 -
 .../readwrite/model/ApduDataGroupValueResponse.go  |   222 -
 .../readwrite/model/ApduDataGroupValueWrite.go     |   222 -
 .../model/ApduDataIndividualAddressRead.go         |   156 -
 .../model/ApduDataIndividualAddressResponse.go     |   156 -
 .../model/ApduDataIndividualAddressWrite.go        |   156 -
 .../knxnetip/readwrite/model/ApduDataMemoryRead.go |   219 -
 .../readwrite/model/ApduDataMemoryResponse.go      |   239 -
 .../readwrite/model/ApduDataMemoryWrite.go         |   156 -
 .../knxnetip/readwrite/model/ApduDataOther.go      |   204 -
 .../knxnetip/readwrite/model/ApduDataRestart.go    |   156 -
 .../readwrite/model/ApduDataUserMessage.go         |   156 -
 .../plc4go/knxnetip/readwrite/model/CEMI.go        |   230 -
 .../readwrite/model/CEMIAdditionalInformation.go   |   185 -
 .../CEMIAdditionalInformationBusmonitorInfo.go     |   356 -
 .../CEMIAdditionalInformationRelativeTimestamp.go  |   237 -
 .../knxnetip/readwrite/model/CEMIPriority.go       |   138 -
 .../knxnetip/readwrite/model/ChannelInformation.go |   173 -
 .../knxnetip/readwrite/model/ComObjectTable.go     |   171 -
 .../readwrite/model/ComObjectTableAddresses.go     | 22636 -------------------
 .../model/ComObjectTableRealisationType1.go        |   268 -
 .../model/ComObjectTableRealisationType2.go        |   268 -
 .../model/ComObjectTableRealisationType6.go        |   201 -
 .../knxnetip/readwrite/model/ComObjectValueType.go |   304 -
 .../knxnetip/readwrite/model/ConnectionRequest.go  |   275 -
 .../model/ConnectionRequestInformation.go          |   202 -
 ...ConnectionRequestInformationDeviceManagement.go |   154 -
 ...ConnectionRequestInformationTunnelConnection.go |   228 -
 .../knxnetip/readwrite/model/ConnectionResponse.go |   330 -
 .../readwrite/model/ConnectionResponseDataBlock.go |   202 -
 .../ConnectionResponseDataBlockDeviceManagement.go |   154 -
 .../ConnectionResponseDataBlockTunnelConnection.go |   202 -
 .../readwrite/model/ConnectionStateRequest.go      |   253 -
 .../readwrite/model/ConnectionStateResponse.go     |   227 -
 .../knxnetip/readwrite/model/DIBDeviceInfo.go      |   430 -
 .../knxnetip/readwrite/model/DIBSuppSvcFamilies.go |   217 -
 .../knxnetip/readwrite/model/DescriptionRequest.go |   201 -
 .../readwrite/model/DescriptionResponse.go         |   238 -
 .../readwrite/model/DeviceConfigurationAck.go      |   201 -
 .../model/DeviceConfigurationAckDataBlock.go       |   225 -
 .../readwrite/model/DeviceConfigurationRequest.go  |   241 -
 .../model/DeviceConfigurationRequestDataBlock.go   |   216 -
 .../knxnetip/readwrite/model/DeviceDescriptor.go   |   607 -
 .../readwrite/model/DeviceDescriptorMediumType.go  |   154 -
 .../readwrite/model/DeviceDescriptorType2.go       |   409 -
 .../knxnetip/readwrite/model/DeviceStatus.go       |   175 -
 .../knxnetip/readwrite/model/DisconnectRequest.go  |   253 -
 .../knxnetip/readwrite/model/DisconnectResponse.go |   227 -
 .../knxnetip/readwrite/model/FirmwareType.go       |   234 -
 .../model/GroupObjectDescriptorRealisationType1.go |   365 -
 .../model/GroupObjectDescriptorRealisationType2.go |   363 -
 .../model/GroupObjectDescriptorRealisationType6.go |   114 -
 .../model/GroupObjectDescriptorRealisationType7.go |   363 -
 .../model/GroupObjectDescriptorRealisationTypeB.go |   339 -
 .../readwrite/model/HPAIControlEndpoint.go         |   236 -
 .../knxnetip/readwrite/model/HPAIDataEndpoint.go   |   236 -
 .../readwrite/model/HPAIDiscoveryEndpoint.go       |   236 -
 .../knxnetip/readwrite/model/HostProtocolCode.go   |   122 -
 .../plc4go/knxnetip/readwrite/model/IPAddress.go   |   152 -
 .../plc4go/knxnetip/readwrite/model/KnxAddress.go  |   197 -
 .../knxnetip/readwrite/model/KnxDatapoint.go       | 13073 -----------
 .../readwrite/model/KnxDatapointMainType.go        |  1382 --
 .../knxnetip/readwrite/model/KnxDatapointType.go   |  7142 ------
 .../knxnetip/readwrite/model/KnxGroupAddress.go    |   171 -
 .../readwrite/model/KnxGroupAddress2Level.go       |   216 -
 .../readwrite/model/KnxGroupAddress3Level.go       |   242 -
 .../readwrite/model/KnxGroupAddressFreeLevel.go    |   190 -
 .../readwrite/model/KnxInterfaceObjectProperty.go  |  5365 -----
 .../readwrite/model/KnxInterfaceObjectType.go      |   543 -
 .../plc4go/knxnetip/readwrite/model/KnxLayer.go    |   130 -
 .../knxnetip/readwrite/model/KnxManufacturer.go    |  9583 --------
 .../plc4go/knxnetip/readwrite/model/KnxMedium.go   |   154 -
 .../knxnetip/readwrite/model/KnxNetIpCore.go       |   190 -
 .../readwrite/model/KnxNetIpDeviceManagement.go    |   190 -
 .../knxnetip/readwrite/model/KnxNetIpMessage.go    |   283 -
 .../knxnetip/readwrite/model/KnxNetIpRouting.go    |   190 -
 .../knxnetip/readwrite/model/KnxNetIpTunneling.go  |   190 -
 .../knxnetip/readwrite/model/KnxNetObjectServer.go |   190 -
 .../model/KnxNetRemoteConfigurationAndDiagnosis.go |   190 -
 .../readwrite/model/KnxNetRemoteLogging.go         |   190 -
 .../plc4go/knxnetip/readwrite/model/KnxProperty.go |  1402 --
 .../readwrite/model/KnxPropertyDataType.go         |  1162 -
 .../plc4go/knxnetip/readwrite/model/LBusmonInd.go  |   317 -
 .../plc4go/knxnetip/readwrite/model/LDataCon.go    |   283 -
 .../knxnetip/readwrite/model/LDataExtended.go      |   372 -
 .../plc4go/knxnetip/readwrite/model/LDataFrame.go  |   346 -
 .../knxnetip/readwrite/model/LDataFrameACK.go      |   163 -
 .../plc4go/knxnetip/readwrite/model/LDataInd.go    |   283 -
 .../plc4go/knxnetip/readwrite/model/LDataReq.go    |   283 -
 .../plc4go/knxnetip/readwrite/model/LPollData.go   |   292 -
 .../knxnetip/readwrite/model/LPollDataCon.go       |   156 -
 .../knxnetip/readwrite/model/LPollDataReq.go       |   156 -
 .../plc4go/knxnetip/readwrite/model/LRawCon.go     |   156 -
 .../plc4go/knxnetip/readwrite/model/LRawInd.go     |   156 -
 .../plc4go/knxnetip/readwrite/model/LRawReq.go     |   156 -
 .../plc4go/knxnetip/readwrite/model/MACAddress.go  |   152 -
 .../readwrite/model/MFuncPropCommandReq.go         |   156 -
 .../knxnetip/readwrite/model/MFuncPropCon.go       |   156 -
 .../readwrite/model/MFuncPropStateReadReq.go       |   156 -
 .../knxnetip/readwrite/model/MPropInfoInd.go       |   156 -
 .../knxnetip/readwrite/model/MPropReadCon.go       |   323 -
 .../knxnetip/readwrite/model/MPropReadReq.go       |   297 -
 .../knxnetip/readwrite/model/MPropWriteCon.go      |   156 -
 .../knxnetip/readwrite/model/MPropWriteReq.go      |   156 -
 .../plc4go/knxnetip/readwrite/model/MResetInd.go   |   156 -
 .../plc4go/knxnetip/readwrite/model/MResetReq.go   |   156 -
 .../model/ProjectInstallationIdentifier.go         |   173 -
 .../knxnetip/readwrite/model/RelativeTimestamp.go  |   149 -
 .../knxnetip/readwrite/model/RoutingIndication.go  |   153 -
 .../knxnetip/readwrite/model/SearchRequest.go      |   201 -
 .../knxnetip/readwrite/model/SearchResponse.go     |   275 -
 .../plc4go/knxnetip/readwrite/model/ServiceId.go   |   195 -
 .../plc4go/knxnetip/readwrite/model/Status.go      |   202 -
 .../readwrite/model/SupportedPhysicalMedia.go      |   479 -
 .../knxnetip/readwrite/model/TDataConnectedInd.go  |   156 -
 .../knxnetip/readwrite/model/TDataConnectedReq.go  |   156 -
 .../knxnetip/readwrite/model/TDataIndividualInd.go |   156 -
 .../knxnetip/readwrite/model/TDataIndividualReq.go |   156 -
 .../knxnetip/readwrite/model/TunnelingRequest.go   |   241 -
 .../readwrite/model/TunnelingRequestDataBlock.go   |   216 -
 .../knxnetip/readwrite/model/TunnelingResponse.go  |   201 -
 .../readwrite/model/TunnelingResponseDataBlock.go  |   225 -
 .../knxnetip/readwrite/model/UnknownMessage.go     |   196 -
 plc4go/internal/plc4go/modbus/Connection.go        |   154 -
 plc4go/internal/plc4go/modbus/Field.go             |   112 -
 plc4go/internal/plc4go/modbus/FieldHandler.go      |    99 -
 plc4go/internal/plc4go/modbus/MessageCodec.go      |   104 -
 plc4go/internal/plc4go/modbus/ModbusAsciiDriver.go |   102 -
 plc4go/internal/plc4go/modbus/ModbusRtuDriver.go   |   102 -
 plc4go/internal/plc4go/modbus/ModbusTcpDriver.go   |   102 -
 plc4go/internal/plc4go/modbus/Reader.go            |   217 -
 plc4go/internal/plc4go/modbus/ValueHandler.go      |    32 -
 plc4go/internal/plc4go/modbus/Writer.go            |   224 -
 .../plc4go/modbus/readwrite/ParserHelper.go        |    69 -
 .../plc4go/modbus/readwrite/XmlParserHelper.go     |    74 -
 .../plc4go/modbus/readwrite/model/DataItem.go      |   657 -
 .../plc4go/modbus/readwrite/model/DriverType.go    |   130 -
 .../plc4go/modbus/readwrite/model/ModbusADU.go     |   174 -
 .../modbus/readwrite/model/ModbusAsciiADU.go       |   260 -
 .../modbus/readwrite/model/ModbusConstants.go      |   151 -
 .../modbus/readwrite/model/ModbusDataType.go       |   448 -
 .../ModbusDeviceInformationConformityLevel.go      |   130 -
 .../model/ModbusDeviceInformationLevel.go          |   138 -
 .../model/ModbusDeviceInformationMoreFollows.go    |   122 -
 .../model/ModbusDeviceInformationObject.go         |   193 -
 .../modbus/readwrite/model/ModbusErrorCode.go      |   186 -
 .../plc4go/modbus/readwrite/model/ModbusPDU.go     |   279 -
 .../readwrite/model/ModbusPDUDiagnosticRequest.go  |   224 -
 .../readwrite/model/ModbusPDUDiagnosticResponse.go |   224 -
 .../modbus/readwrite/model/ModbusPDUError.go       |   209 -
 .../model/ModbusPDUGetComEventCounterRequest.go    |   161 -
 .../model/ModbusPDUGetComEventCounterResponse.go   |   224 -
 .../model/ModbusPDUGetComEventLogRequest.go        |   161 -
 .../model/ModbusPDUGetComEventLogResponse.go       |   296 -
 .../ModbusPDUMaskWriteHoldingRegisterRequest.go    |   250 -
 .../ModbusPDUMaskWriteHoldingRegisterResponse.go   |   250 -
 .../readwrite/model/ModbusPDUReadCoilsRequest.go   |   224 -
 .../readwrite/model/ModbusPDUReadCoilsResponse.go  |   218 -
 .../ModbusPDUReadDeviceIdentificationRequest.go    |   270 -
 .../ModbusPDUReadDeviceIdentificationResponse.go   |   439 -
 .../model/ModbusPDUReadDiscreteInputsRequest.go    |   224 -
 .../model/ModbusPDUReadDiscreteInputsResponse.go   |   218 -
 .../model/ModbusPDUReadExceptionStatusRequest.go   |   161 -
 .../model/ModbusPDUReadExceptionStatusResponse.go  |   198 -
 .../model/ModbusPDUReadFifoQueueRequest.go         |   198 -
 .../model/ModbusPDUReadFifoQueueResponse.go        |   255 -
 .../model/ModbusPDUReadFileRecordRequest.go        |   249 -
 .../model/ModbusPDUReadFileRecordRequestItem.go    |   221 -
 .../model/ModbusPDUReadFileRecordResponse.go       |   249 -
 .../model/ModbusPDUReadFileRecordResponseItem.go   |   193 -
 .../model/ModbusPDUReadHoldingRegistersRequest.go  |   224 -
 .../model/ModbusPDUReadHoldingRegistersResponse.go |   218 -
 .../model/ModbusPDUReadInputRegistersRequest.go    |   224 -
 .../model/ModbusPDUReadInputRegistersResponse.go   |   218 -
 ...sPDUReadWriteMultipleHoldingRegistersRequest.go |   322 -
 ...PDUReadWriteMultipleHoldingRegistersResponse.go |   218 -
 .../model/ModbusPDUReportServerIdRequest.go        |   161 -
 .../model/ModbusPDUReportServerIdResponse.go       |   218 -
 .../model/ModbusPDUWriteFileRecordRequest.go       |   249 -
 .../model/ModbusPDUWriteFileRecordRequestItem.go   |   241 -
 .../model/ModbusPDUWriteFileRecordResponse.go      |   249 -
 .../model/ModbusPDUWriteFileRecordResponseItem.go  |   241 -
 .../model/ModbusPDUWriteMultipleCoilsRequest.go    |   270 -
 .../model/ModbusPDUWriteMultipleCoilsResponse.go   |   224 -
 ...odbusPDUWriteMultipleHoldingRegistersRequest.go |   270 -
 ...dbusPDUWriteMultipleHoldingRegistersResponse.go |   224 -
 .../model/ModbusPDUWriteSingleCoilRequest.go       |   224 -
 .../model/ModbusPDUWriteSingleCoilResponse.go      |   224 -
 .../model/ModbusPDUWriteSingleRegisterRequest.go   |   224 -
 .../model/ModbusPDUWriteSingleRegisterResponse.go  |   224 -
 .../plc4go/modbus/readwrite/model/ModbusRtuADU.go  |   260 -
 .../plc4go/modbus/readwrite/model/ModbusTcpADU.go  |   308 -
 plc4go/internal/plc4go/s7/Connection.go            |   460 -
 plc4go/internal/plc4go/s7/Driver.go                |   110 -
 plc4go/internal/plc4go/s7/DriverContext.go         |    93 -
 plc4go/internal/plc4go/s7/Field.go                 |   186 -
 plc4go/internal/plc4go/s7/FieldHandler.go          |   344 -
 plc4go/internal/plc4go/s7/MessageCodec.go          |   102 -
 plc4go/internal/plc4go/s7/Reader.go                |   294 -
 plc4go/internal/plc4go/s7/TsapIdEncoder.go         |    41 -
 plc4go/internal/plc4go/s7/ValueHandler.go          |    32 -
 plc4go/internal/plc4go/s7/Writer.go                |   249 -
 .../internal/plc4go/s7/readwrite/ParserHelper.go   |   130 -
 .../plc4go/s7/readwrite/XmlParserHelper.go         |   147 -
 .../model/AlarmMessageAckObjectPushType.go         |   337 -
 .../s7/readwrite/model/AlarmMessageAckPushType.go  |   258 -
 .../readwrite/model/AlarmMessageAckResponseType.go |   220 -
 .../s7/readwrite/model/AlarmMessageAckType.go      |   223 -
 .../readwrite/model/AlarmMessageObjectAckType.go   |   336 -
 .../readwrite/model/AlarmMessageObjectPushType.go  |   457 -
 .../readwrite/model/AlarmMessageObjectQueryType.go |   455 -
 .../s7/readwrite/model/AlarmMessagePushType.go     |   258 -
 .../s7/readwrite/model/AlarmMessageQueryType.go    |   328 -
 .../plc4go/s7/readwrite/model/AlarmStateType.go    |   154 -
 .../plc4go/s7/readwrite/model/AlarmType.go         |   130 -
 .../s7/readwrite/model/AssociatedValueType.go      |   265 -
 .../plc4go/s7/readwrite/model/COTPPacket.go        |   329 -
 .../readwrite/model/COTPPacketConnectionRequest.go |   259 -
 .../model/COTPPacketConnectionResponse.go          |   259 -
 .../plc4go/s7/readwrite/model/COTPPacketData.go    |   222 -
 .../readwrite/model/COTPPacketDisconnectRequest.go |   259 -
 .../model/COTPPacketDisconnectResponse.go          |   222 -
 .../s7/readwrite/model/COTPPacketTpduError.go      |   222 -
 .../plc4go/s7/readwrite/model/COTPParameter.go     |   211 -
 .../s7/readwrite/model/COTPParameterCalledTsap.go  |   193 -
 .../s7/readwrite/model/COTPParameterCallingTsap.go |   193 -
 .../s7/readwrite/model/COTPParameterChecksum.go    |   193 -
 ...COTPParameterDisconnectAdditionalInformation.go |   196 -
 .../s7/readwrite/model/COTPParameterTpduSize.go    |   204 -
 .../plc4go/s7/readwrite/model/COTPProtocolClass.go |   146 -
 .../plc4go/s7/readwrite/model/COTPTpduSize.go      |   208 -
 .../s7/readwrite/model/CpuSubscribeEvents.go       |   138 -
 .../internal/plc4go/s7/readwrite/model/DataItem.go |   489 -
 .../s7/readwrite/model/DataTransportErrorCode.go   |   154 -
 .../plc4go/s7/readwrite/model/DataTransportSize.go |   208 -
 .../plc4go/s7/readwrite/model/DateAndTime.go       |   310 -
 .../plc4go/s7/readwrite/model/DeviceGroup.go       |   130 -
 .../plc4go/s7/readwrite/model/EventType.go         |   138 -
 .../plc4go/s7/readwrite/model/MemoryArea.go        |   232 -
 .../s7/readwrite/model/ModeTransitionType.go       |   178 -
 .../plc4go/s7/readwrite/model/QueryType.go         |   130 -
 .../plc4go/s7/readwrite/model/S7Address.go         |   183 -
 .../plc4go/s7/readwrite/model/S7AddressAny.go      |   371 -
 .../s7/readwrite/model/S7DataAlarmMessage.go       |   228 -
 .../plc4go/s7/readwrite/model/S7Message.go         |   417 -
 .../s7/readwrite/model/S7MessageObjectRequest.go   |   384 -
 .../s7/readwrite/model/S7MessageObjectResponse.go  |   264 -
 .../plc4go/s7/readwrite/model/S7MessageRequest.go  |   157 -
 .../plc4go/s7/readwrite/model/S7MessageResponse.go |   220 -
 .../s7/readwrite/model/S7MessageResponseData.go    |   220 -
 .../plc4go/s7/readwrite/model/S7MessageUserData.go |   157 -
 .../plc4go/s7/readwrite/model/S7Parameter.go       |   197 -
 .../readwrite/model/S7ParameterModeTransition.go   |   341 -
 .../readwrite/model/S7ParameterReadVarRequest.go   |   237 -
 .../readwrite/model/S7ParameterReadVarResponse.go  |   194 -
 .../model/S7ParameterSetupCommunication.go         |   272 -
 .../s7/readwrite/model/S7ParameterUserData.go      |   237 -
 .../s7/readwrite/model/S7ParameterUserDataItem.go  |   183 -
 .../model/S7ParameterUserDataItemCPUFunctions.go   |   413 -
 .../readwrite/model/S7ParameterWriteVarRequest.go  |   237 -
 .../readwrite/model/S7ParameterWriteVarResponse.go |   194 -
 .../plc4go/s7/readwrite/model/S7Payload.go         |   178 -
 .../plc4go/s7/readwrite/model/S7PayloadAlarm8.go   |   212 -
 .../s7/readwrite/model/S7PayloadAlarmAckInd.go     |   212 -
 .../plc4go/s7/readwrite/model/S7PayloadAlarmS.go   |   212 -
 .../plc4go/s7/readwrite/model/S7PayloadAlarmSC.go  |   212 -
 .../plc4go/s7/readwrite/model/S7PayloadAlarmSQ.go  |   212 -
 .../readwrite/model/S7PayloadDiagnosticMessage.go  |   368 -
 .../plc4go/s7/readwrite/model/S7PayloadNotify.go   |   212 -
 .../plc4go/s7/readwrite/model/S7PayloadNotify8.go  |   212 -
 .../s7/readwrite/model/S7PayloadReadVarResponse.go |   223 -
 .../plc4go/s7/readwrite/model/S7PayloadUserData.go |   223 -
 .../s7/readwrite/model/S7PayloadUserDataItem.go    |   302 -
 .../S7PayloadUserDataItemCpuFunctionAlarmAck.go    |   270 -
 ...yloadUserDataItemCpuFunctionAlarmAckResponse.go |   267 -
 .../S7PayloadUserDataItemCpuFunctionAlarmQuery.go  |   441 -
 ...oadUserDataItemCpuFunctionAlarmQueryResponse.go |   333 -
 ...ayloadUserDataItemCpuFunctionMsgSubscription.go |   333 -
 ...aItemCpuFunctionMsgSubscriptionAlarmResponse.go |   316 -
 ...erDataItemCpuFunctionMsgSubscriptionResponse.go |   164 -
 ...ataItemCpuFunctionMsgSubscriptionSysResponse.go |   227 -
 ...PayloadUserDataItemCpuFunctionReadSzlRequest.go |   238 -
 ...ayloadUserDataItemCpuFunctionReadSzlResponse.go |   342 -
 .../s7/readwrite/model/S7PayloadWriteVarRequest.go |   223 -
 .../readwrite/model/S7PayloadWriteVarResponse.go   |   223 -
 .../s7/readwrite/model/S7VarPayloadDataItem.go     |   284 -
 .../s7/readwrite/model/S7VarPayloadStatusItem.go   |   160 -
 .../readwrite/model/S7VarRequestParameterItem.go   |   183 -
 .../model/S7VarRequestParameterItemAddress.go      |   218 -
 plc4go/internal/plc4go/s7/readwrite/model/State.go |   317 -
 .../plc4go/s7/readwrite/model/StaticHelper.go      |   181 -
 .../plc4go/s7/readwrite/model/SyntaxIdType.go      |   210 -
 .../plc4go/s7/readwrite/model/SzlDataTreeItem.go   |   248 -
 plc4go/internal/plc4go/s7/readwrite/model/SzlId.go |   219 -
 .../s7/readwrite/model/SzlModuleTypeClass.go       |   138 -
 .../plc4go/s7/readwrite/model/SzlSublist.go        |   258 -
 .../plc4go/s7/readwrite/model/TPKTPacket.go        |   238 -
 .../plc4go/s7/readwrite/model/TransportSize.go     |  1666 --
 plc4go/internal/plc4go/s7/s7Io_test.go             |   950 -
 plc4go/internal/plc4go/simulated/Connection.go     |   243 -
 .../internal/plc4go/simulated/Connection_test.go   |   735 -
 plc4go/internal/plc4go/simulated/Device.go         |    76 -
 plc4go/internal/plc4go/simulated/Device_test.go    |   288 -
 plc4go/internal/plc4go/simulated/Driver.go         |    79 -
 plc4go/internal/plc4go/simulated/Driver_test.go    |   326 -
 plc4go/internal/plc4go/simulated/Field.go          |    71 -
 plc4go/internal/plc4go/simulated/FieldHandler.go   |   103 -
 .../internal/plc4go/simulated/FieldHandler_test.go |   169 -
 plc4go/internal/plc4go/simulated/Field_test.go     |   291 -
 plc4go/internal/plc4go/simulated/Reader.go         |    94 -
 plc4go/internal/plc4go/simulated/Reader_test.go    |   202 -
 plc4go/internal/plc4go/simulated/Writer.go         |    86 -
 plc4go/internal/plc4go/simulated/Writer_test.go    |   214 -
 .../plc4go/simulated/readwrite/ParserHelper.go     |    49 -
 .../plc4go/simulated/readwrite/XmlParserHelper.go  |    58 -
 .../plc4go/simulated/readwrite/model/DataItem.go   |   643 -
 .../plc4go/simulated/readwrite/model/Dummy.go      |   149 -
 .../readwrite/model/SimulatedDataTypeSizes.go      |   448 -
 plc4go/internal/plc4go/spi/Message.go              |    28 -
 plc4go/internal/plc4go/spi/PlcDiscoverer.go        |    29 -
 plc4go/internal/plc4go/spi/Tracer.go               |   129 -
 plc4go/internal/plc4go/spi/TransportAware.go       |    31 -
 .../plc4go/spi/TransportInstanceExposer.go         |    26 -
 plc4go/internal/plc4go/spi/default/DefaultCodec.go |   310 -
 .../plc4go/spi/default/DefaultConnection.go        |   351 -
 .../internal/plc4go/spi/default/DefaultDriver.go   |    96 -
 .../interceptors/SingleItemRequestInterceptor.go   |   227 -
 .../plc4go/spi/model/DefaultBrowseRequest.go       |   103 -
 .../plc4go/spi/model/DefaultPlcReadRequest.go      |   174 -
 .../plc4go/spi/model/DefaultPlcReadResponse.go     |   115 -
 .../spi/model/DefaultPlcSubscriptionEvent.go       |   104 -
 .../spi/model/DefaultPlcSubscriptionRequest.go     |   185 -
 .../spi/model/DefaultPlcSubscriptionResponse.go    |    91 -
 .../plc4go/spi/model/DefaultPlcWriteRequest.go     |   232 -
 .../plc4go/spi/model/DefaultPlcWriteResponse.go    |    82 -
 .../plc4go/spi/testutils/DriverTestRunner.go       |   713 -
 .../plc4go/spi/testutils/ManualTestRunner.go       |   188 -
 .../spi/testutils/ParserSerializerTestRunner.go    |   257 -
 .../plc4go/spi/transports/pcap/Transport.go        |   226 -
 .../plc4go/spi/transports/serial/Transport.go      |   183 -
 .../plc4go/spi/transports/tcp/Transport.go         |   192 -
 .../plc4go/spi/transports/test/Transport.go        |   129 -
 .../plc4go/spi/transports/udp/Transport.go         |   221 -
 plc4go/internal/plc4go/spi/values/BINT.go          |   146 -
 plc4go/internal/plc4go/spi/values/BOOL.go          |    79 -
 plc4go/internal/plc4go/spi/values/BREAL.go         |   178 -
 plc4go/internal/plc4go/spi/values/BYTE.go          |   103 -
 plc4go/internal/plc4go/spi/values/CHAR.go          |    52 -
 plc4go/internal/plc4go/spi/values/DATE.go          |    71 -
 plc4go/internal/plc4go/spi/values/DATE_AND_TIME.go |    58 -
 plc4go/internal/plc4go/spi/values/DINT.go          |   142 -
 plc4go/internal/plc4go/spi/values/DWORD.go         |   102 -
 plc4go/internal/plc4go/spi/values/INT.go           |   135 -
 plc4go/internal/plc4go/spi/values/LINT.go          |   149 -
 plc4go/internal/plc4go/spi/values/LREAL.go         |   165 -
 plc4go/internal/plc4go/spi/values/LTIME.go         |    63 -
 plc4go/internal/plc4go/spi/values/LWORD.go         |   118 -
 plc4go/internal/plc4go/spi/values/PlcBitString.go  |    81 -
 plc4go/internal/plc4go/spi/values/PlcByteArray.go  |    75 -
 plc4go/internal/plc4go/spi/values/PlcList.go       |    78 -
 plc4go/internal/plc4go/spi/values/PlcStruct.go     |   106 -
 plc4go/internal/plc4go/spi/values/REAL.go          |   159 -
 plc4go/internal/plc4go/spi/values/RawPlcValue.go   |    83 -
 plc4go/internal/plc4go/spi/values/SINT.go          |   127 -
 plc4go/internal/plc4go/spi/values/STRING.go        |    53 -
 plc4go/internal/plc4go/spi/values/TIME.go          |    63 -
 plc4go/internal/plc4go/spi/values/TIME_OF_DAY.go   |    74 -
 plc4go/internal/plc4go/spi/values/UDINT.go         |   135 -
 plc4go/internal/plc4go/spi/values/UINT.go          |   121 -
 plc4go/internal/plc4go/spi/values/ULINT.go         |   149 -
 plc4go/internal/plc4go/spi/values/USINT.go         |   107 -
 plc4go/internal/plc4go/spi/values/WCHAR.go         |    54 -
 plc4go/internal/plc4go/spi/values/WORD.go          |    94 -
 plc4go/internal/plc4go/spi/values/WSTRING.go       |    54 -
 plc4go/internal/{plc4go => }/s7/Configuration.go   |     0
 plc4go/internal/s7/Connection.go                   |   460 +
 plc4go/internal/{plc4go => }/s7/ControllerType.go  |     0
 plc4go/internal/s7/Driver.go                       |   110 +
 plc4go/internal/s7/DriverContext.go                |    93 +
 plc4go/internal/s7/Field.go                        |   186 +
 plc4go/internal/s7/FieldHandler.go                 |   344 +
 plc4go/internal/s7/MessageCodec.go                 |   102 +
 plc4go/internal/s7/Reader.go                       |   294 +
 plc4go/internal/s7/TsapIdEncoder.go                |    41 +
 plc4go/internal/s7/ValueHandler.go                 |    32 +
 plc4go/internal/s7/Writer.go                       |   249 +
 .../internal/{plc4go => }/s7/fieldtype_string.go   |     0
 plc4go/internal/s7/s7Io_test.go                    |   950 +
 plc4go/internal/simulated/Connection.go            |   243 +
 plc4go/internal/simulated/Connection_test.go       |   735 +
 plc4go/internal/simulated/Device.go                |    76 +
 plc4go/internal/simulated/Device_test.go           |   288 +
 plc4go/internal/simulated/Driver.go                |    79 +
 plc4go/internal/simulated/Driver_test.go           |   326 +
 plc4go/internal/simulated/Field.go                 |    71 +
 plc4go/internal/simulated/FieldHandler.go          |   103 +
 plc4go/internal/simulated/FieldHandler_test.go     |   169 +
 plc4go/internal/simulated/Field_test.go            |   291 +
 plc4go/internal/simulated/Reader.go                |    94 +
 plc4go/internal/simulated/Reader_test.go           |   202 +
 .../{plc4go => }/simulated/ValueHandler.go         |     0
 plc4go/internal/simulated/Writer.go                |    86 +
 plc4go/internal/simulated/Writer_test.go           |   214 +
 plc4go/internal/{plc4go => }/spi/HandlerExposer.go |     0
 plc4go/internal/spi/Message.go                     |    28 +
 plc4go/internal/{plc4go => }/spi/MessageCodec.go   |     0
 plc4go/internal/{plc4go => }/spi/PlcBrowser.go     |     0
 plc4go/internal/{plc4go => }/spi/PlcConnection.go  |     0
 plc4go/internal/spi/PlcDiscoverer.go               |    29 +
 .../internal/{plc4go => }/spi/PlcFieldHandler.go   |     0
 plc4go/internal/{plc4go => }/spi/PlcReader.go      |     0
 plc4go/internal/{plc4go => }/spi/PlcSubscriber.go  |     0
 .../internal/{plc4go => }/spi/PlcValueHandler.go   |     0
 plc4go/internal/{plc4go => }/spi/PlcWriter.go      |     0
 .../{plc4go => }/spi/RequestTransactionManager.go  |     0
 plc4go/internal/spi/Tracer.go                      |   129 +
 plc4go/internal/spi/TransportAware.go              |    31 +
 plc4go/internal/spi/TransportInstanceExposer.go    |    26 +
 plc4go/internal/spi/default/DefaultCodec.go        |   310 +
 plc4go/internal/spi/default/DefaultConnection.go   |   351 +
 plc4go/internal/spi/default/DefaultDriver.go       |    96 +
 plc4go/internal/{plc4go => }/spi/default/init.go   |     0
 .../spi/interceptors/RequestInterceptor.go         |     0
 .../interceptors/SingleItemRequestInterceptor.go   |   227 +
 plc4go/internal/spi/model/DefaultBrowseRequest.go  |   103 +
 .../spi/model/DefaultPlcBrowseEvent.go             |     0
 .../spi/model/DefaultPlcBrowseQueryResult.go       |     0
 .../spi/model/DefaultPlcBrowseRequestResult.go     |     0
 .../spi/model/DefaultPlcDiscoveryEvent.go          |     0
 plc4go/internal/spi/model/DefaultPlcReadRequest.go |   174 +
 .../spi/model/DefaultPlcReadRequestResult.go       |     0
 .../internal/spi/model/DefaultPlcReadResponse.go   |   115 +
 .../spi/model/DefaultPlcSubscriptionEvent.go       |   104 +
 .../spi/model/DefaultPlcSubscriptionRequest.go     |   185 +
 .../model/DefaultPlcSubscriptionRequestResult.go   |     0
 .../spi/model/DefaultPlcSubscriptionResponse.go    |    91 +
 .../spi/model/DefaultPlcUnsubscriptionRequest.go   |     0
 .../model/DefaultPlcUnsubscriptionRequestResult.go |     0
 .../spi/model/DefaultPlcUnsubscriptionResponse.go  |     0
 .../internal/spi/model/DefaultPlcWriteRequest.go   |   232 +
 .../spi/model/DefaultPlcWriteRequestResult.go      |     0
 .../internal/spi/model/DefaultPlcWriteResponse.go  |    82 +
 .../{plc4go => }/spi/model/DefaultRequest.go       |     0
 .../{plc4go => }/spi/model/DefaultResponse.go      |     0
 .../{plc4go => }/spi/options/DiscoveryOption.go    |     0
 plc4go/internal/{plc4go => }/spi/options/Option.go |     0
 .../{plc4go => }/spi/plcerrors/TimeoutError.go     |     0
 plc4go/internal/spi/testutils/DriverTestRunner.go  |   713 +
 plc4go/internal/spi/testutils/ManualTestRunner.go  |   188 +
 .../spi/testutils/ParserSerializerTestRunner.go    |   257 +
 .../{plc4go => }/spi/testutils/TestUtils.go        |     0
 .../{plc4go => }/spi/testutils/steptype_string.go  |     0
 .../{plc4go => }/spi/transports/Transport.go       |     0
 .../spi/transports/TransportInstance.go            |     0
 plc4go/internal/spi/transports/pcap/Transport.go   |   226 +
 plc4go/internal/spi/transports/serial/Transport.go |   183 +
 plc4go/internal/spi/transports/tcp/Transport.go    |   192 +
 plc4go/internal/spi/transports/test/Transport.go   |   129 +
 plc4go/internal/spi/transports/udp/Transport.go    |   221 +
 .../spi/transports/utils/TransportLogger.go        |     0
 plc4go/internal/{plc4go => }/spi/utils/Buffer.go   |     0
 .../internal/{plc4go => }/spi/utils/CastUtils.go   |     0
 .../internal/{plc4go => }/spi/utils/IdGenerator.go |     0
 .../internal/{plc4go => }/spi/utils/MultiError.go  |     0
 .../{plc4go => }/spi/utils/PositionAware.go        |     0
 .../internal/{plc4go => }/spi/utils/ReadBuffer.go  |     0
 .../{plc4go => }/spi/utils/ReadBufferByteBased.go  |     0
 .../spi/utils/ReadBufferByteBased_test.go          |     0
 .../{plc4go => }/spi/utils/ReadBufferJsonBased.go  |     0
 .../{plc4go => }/spi/utils/ReadBufferXmlBased.go   |     0
 plc4go/internal/{plc4go => }/spi/utils/Regexp.go   |     0
 .../{plc4go => }/spi/utils/Serializable.go         |     0
 plc4go/internal/{plc4go => }/spi/utils/Utils.go    |     0
 .../internal/{plc4go => }/spi/utils/WriteBuffer.go |     0
 .../{plc4go => }/spi/utils/WriteBufferBoxBased.go  |     0
 .../{plc4go => }/spi/utils/WriteBufferByteBased.go |     0
 .../{plc4go => }/spi/utils/WriteBufferJsonBased.go |     0
 .../{plc4go => }/spi/utils/WriteBufferXmlBased.go  |     0
 plc4go/internal/{plc4go => }/spi/utils/asciiBox.go |     0
 .../{plc4go => }/spi/utils/asciiBox_test.go        |     0
 .../{plc4go => }/spi/utils/bufferCommons.go        |     0
 .../internal/{plc4go => }/spi/utils/dumpUtils.go   |     0
 .../{plc4go => }/spi/utils/dumpUtils_test.go       |     0
 plc4go/internal/{plc4go => }/spi/utils/hex.go      |     0
 plc4go/internal/{plc4go => }/spi/utils/hex_test.go |     0
 plc4go/internal/spi/values/BINT.go                 |   146 +
 plc4go/internal/spi/values/BOOL.go                 |    79 +
 plc4go/internal/spi/values/BREAL.go                |   178 +
 plc4go/internal/spi/values/BYTE.go                 |   103 +
 plc4go/internal/spi/values/CHAR.go                 |    52 +
 plc4go/internal/spi/values/DATE.go                 |    71 +
 plc4go/internal/spi/values/DATE_AND_TIME.go        |    58 +
 plc4go/internal/spi/values/DINT.go                 |   142 +
 plc4go/internal/spi/values/DWORD.go                |   102 +
 .../spi/values/IEC61131ValueHandler.go             |     0
 plc4go/internal/spi/values/INT.go                  |   135 +
 plc4go/internal/spi/values/LINT.go                 |   149 +
 plc4go/internal/spi/values/LREAL.go                |   165 +
 plc4go/internal/spi/values/LTIME.go                |    63 +
 plc4go/internal/spi/values/LWORD.go                |   118 +
 plc4go/internal/{plc4go => }/spi/values/NULL.go    |     0
 plc4go/internal/spi/values/PlcBitString.go         |    81 +
 plc4go/internal/spi/values/PlcByteArray.go         |    75 +
 plc4go/internal/spi/values/PlcList.go              |    78 +
 .../spi/values/PlcSimpleValueAdapter.go            |     0
 plc4go/internal/spi/values/PlcStruct.go            |   106 +
 .../{plc4go => }/spi/values/PlcValueAdapter.go     |     0
 plc4go/internal/spi/values/REAL.go                 |   159 +
 plc4go/internal/spi/values/RawPlcValue.go          |    83 +
 plc4go/internal/spi/values/SINT.go                 |   127 +
 plc4go/internal/spi/values/STRING.go               |    53 +
 plc4go/internal/spi/values/TIME.go                 |    63 +
 plc4go/internal/spi/values/TIME_OF_DAY.go          |    74 +
 plc4go/internal/spi/values/UDINT.go                |   135 +
 plc4go/internal/spi/values/UINT.go                 |   121 +
 plc4go/internal/spi/values/ULINT.go                |   149 +
 plc4go/internal/spi/values/USINT.go                |   107 +
 plc4go/internal/spi/values/WCHAR.go                |    54 +
 plc4go/internal/spi/values/WORD.go                 |    94 +
 plc4go/internal/spi/values/WSTRING.go              |    54 +
 plc4go/pkg/plc4go/cache/plc_connection_cache.go    |     4 +-
 .../pkg/plc4go/cache/plc_connection_cache_test.go  |     6 +-
 plc4go/pkg/plc4go/driver.go                        |     4 +-
 plc4go/pkg/plc4go/driverManager.go                 |     4 +-
 plc4go/pkg/plc4go/drivers/drivers.go               |    16 +-
 plc4go/pkg/plc4go/transports/transports.go         |     8 +-
 plc4go/pom.xml                                     |    30 +-
 plc4go/protocols/abeth/readwrite/ParserHelper.go   |    49 +
 .../protocols/abeth/readwrite/XmlParserHelper.go   |    60 +
 .../model/CIPEncapsulationConnectionRequest.go     |   158 +
 .../model/CIPEncapsulationConnectionResponse.go    |   158 +
 .../readwrite/model/CIPEncapsulationPacket.go      |   361 +
 .../readwrite/model/CIPEncapsulationReadRequest.go |   206 +
 .../model/CIPEncapsulationReadResponse.go          |   209 +
 .../readwrite/model/DF1CommandRequestMessage.go    |   206 +
 ...mandResponseMessageProtectedTypedLogicalRead.go |   223 +
 .../abeth/readwrite/model/DF1RequestCommand.go     |   183 +
 .../abeth/readwrite/model/DF1RequestMessage.go     |   315 +
 .../model/DF1RequestProtectedTypedLogicalRead.go   |   294 +
 .../abeth/readwrite/model/DF1ResponseMessage.go    |   343 +
 plc4go/protocols/ads/readwrite/ParserHelper.go     |    78 +
 plc4go/protocols/ads/readwrite/XmlParserHelper.go  |    85 +
 .../model/AdsAddDeviceNotificationRequest.go       |   375 +
 .../model/AdsAddDeviceNotificationResponse.go      |   231 +
 plc4go/protocols/ads/readwrite/model/AdsData.go    |   207 +
 .../protocols/ads/readwrite/model/AdsDataType.go   |   783 +
 .../model/AdsDeleteDeviceNotificationRequest.go    |   194 +
 .../model/AdsDeleteDeviceNotificationResponse.go   |   205 +
 .../model/AdsDeviceNotificationRequest.go          |   272 +
 .../model/AdsDeviceNotificationResponse.go         |   157 +
 .../ads/readwrite/model/AdsInvalidRequest.go       |   157 +
 .../ads/readwrite/model/AdsInvalidResponse.go      |   157 +
 .../ads/readwrite/model/AdsMultiRequestItem.go     |   171 +
 .../ads/readwrite/model/AdsMultiRequestItemRead.go |   242 +
 .../model/AdsMultiRequestItemReadWrite.go          |   268 +
 .../readwrite/model/AdsMultiRequestItemWrite.go    |   242 +
 .../ads/readwrite/model/AdsNotificationSample.go   |   200 +
 .../readwrite/model/AdsReadDeviceInfoRequest.go    |   157 +
 .../readwrite/model/AdsReadDeviceInfoResponse.go   |   312 +
 .../ads/readwrite/model/AdsReadRequest.go          |   246 +
 .../ads/readwrite/model/AdsReadResponse.go         |   251 +
 .../ads/readwrite/model/AdsReadStateRequest.go     |   157 +
 .../ads/readwrite/model/AdsReadStateResponse.go    |   257 +
 .../ads/readwrite/model/AdsReadWriteRequest.go     |   344 +
 .../ads/readwrite/model/AdsReadWriteResponse.go    |   251 +
 .../ads/readwrite/model/AdsStampHeader.go          |   223 +
 .../ads/readwrite/model/AdsWriteControlRequest.go  |   266 +
 .../ads/readwrite/model/AdsWriteControlResponse.go |   205 +
 .../ads/readwrite/model/AdsWriteRequest.go         |   266 +
 .../ads/readwrite/model/AdsWriteResponse.go        |   205 +
 plc4go/protocols/ads/readwrite/model/AmsNetId.go   |   269 +
 plc4go/protocols/ads/readwrite/model/AmsPacket.go  |   413 +
 .../readwrite/model/AmsSerialAcknowledgeFrame.go   |   269 +
 .../ads/readwrite/model/AmsSerialFrame.go          |   304 +
 .../ads/readwrite/model/AmsSerialResetFrame.go     |   269 +
 .../protocols/ads/readwrite/model/AmsTCPPacket.go  |   203 +
 plc4go/protocols/ads/readwrite/model/CommandId.go  |   186 +
 plc4go/protocols/ads/readwrite/model/DataItem.go   |   369 +
 .../ads/readwrite/model/ReservedIndexGroups.go     |   346 +
 plc4go/protocols/ads/readwrite/model/ReturnCode.go |  1082 +
 plc4go/protocols/ads/readwrite/model/State.go      |   367 +
 .../protocols/ads/readwrite/model/StaticHelper.go  |    47 +
 .../protocols/bacnetip/readwrite/ParserHelper.go   |   927 +
 .../bacnetip/readwrite/XmlParserHelper.go          |  1057 +
 plc4go/protocols/bacnetip/readwrite/model/APDU.go  |   202 +
 .../bacnetip/readwrite/model/APDUAbort.go          |   282 +
 .../bacnetip/readwrite/model/APDUComplexAck.go     |   463 +
 .../readwrite/model/APDUConfirmedRequest.go        |   563 +
 .../bacnetip/readwrite/model/APDUError.go          |   293 +
 .../bacnetip/readwrite/model/APDUReject.go         |   256 +
 .../bacnetip/readwrite/model/APDUSegmentAck.go     |   323 +
 .../bacnetip/readwrite/model/APDUSimpleAck.go      |   245 +
 .../readwrite/model/APDUUnconfirmedRequest.go      |   230 +
 .../bacnetip/readwrite/model/APDUUnknown.go        |   196 +
 .../bacnetip/readwrite/model/BACnetAbortReason.go  |   210 +
 .../readwrite/model/BACnetAbortReasonTagged.go     |   200 +
 .../BACnetAccessAuthenticationFactorDisable.go     |   162 +
 ...ACnetAccessAuthenticationFactorDisableTagged.go |   246 +
 .../model/BACnetAccessCredentialDisable.go         |   146 +
 .../model/BACnetAccessCredentialDisableReason.go   |   194 +
 .../BACnetAccessCredentialDisableReasonTagged.go   |   246 +
 .../model/BACnetAccessCredentialDisableTagged.go   |   246 +
 .../bacnetip/readwrite/model/BACnetAccessEvent.go  |   546 +
 .../readwrite/model/BACnetAccessEventTagged.go     |   246 +
 .../readwrite/model/BACnetAccessPassbackMode.go    |   130 +
 .../model/BACnetAccessPassbackModeTagged.go        |   197 +
 .../readwrite/model/BACnetAccessUserType.go        |   138 +
 .../readwrite/model/BACnetAccessUserTypeTagged.go  |   246 +
 .../model/BACnetAccessZoneOccupancyState.go        |   170 +
 .../model/BACnetAccessZoneOccupancyStateTagged.go  |   246 +
 .../bacnetip/readwrite/model/BACnetAction.go       |   122 +
 .../readwrite/model/BACnetActionCommand.go         |   511 +
 .../bacnetip/readwrite/model/BACnetActionList.go   |   245 +
 .../bacnetip/readwrite/model/BACnetActionTagged.go |   197 +
 .../bacnetip/readwrite/model/BACnetAddress.go      |   196 +
 .../readwrite/model/BACnetApplicationTag.go        |   282 +
 .../model/BACnetApplicationTagBitString.go         |   199 +
 .../readwrite/model/BACnetApplicationTagBoolean.go |   225 +
 .../model/BACnetApplicationTagCharacterString.go   |   225 +
 .../readwrite/model/BACnetApplicationTagDate.go    |   199 +
 .../readwrite/model/BACnetApplicationTagDouble.go  |   225 +
 .../model/BACnetApplicationTagEnumerated.go        |   225 +
 .../readwrite/model/BACnetApplicationTagNull.go    |   151 +
 .../model/BACnetApplicationTagObjectIdentifier.go  |   242 +
 .../model/BACnetApplicationTagOctetString.go       |   225 +
 .../readwrite/model/BACnetApplicationTagReal.go    |   225 +
 .../model/BACnetApplicationTagSignedInteger.go     |   225 +
 .../readwrite/model/BACnetApplicationTagTime.go    |   199 +
 .../model/BACnetApplicationTagUnsignedInteger.go   |   225 +
 .../model/BACnetAuthenticationFactorType.go        |   306 +
 .../model/BACnetAuthenticationFactorTypeTagged.go  |   197 +
 .../readwrite/model/BACnetAuthenticationStatus.go  |   162 +
 .../model/BACnetAuthenticationStatusTagged.go      |   197 +
 .../model/BACnetAuthorizationExemption.go          |   170 +
 .../model/BACnetAuthorizationExemptionTagged.go    |   246 +
 .../readwrite/model/BACnetAuthorizationMode.go     |   162 +
 .../model/BACnetAuthorizationModeTagged.go         |   246 +
 .../bacnetip/readwrite/model/BACnetBackupState.go  |   162 +
 .../readwrite/model/BACnetBackupStateTagged.go     |   197 +
 .../readwrite/model/BACnetBinaryLightingPV.go      |   162 +
 .../model/BACnetBinaryLightingPVTagged.go          |   246 +
 .../bacnetip/readwrite/model/BACnetBinaryPV.go     |   122 +
 .../readwrite/model/BACnetBinaryPVTagged.go        |   197 +
 .../readwrite/model/BACnetCharacterEncoding.go     |   154 +
 .../bacnetip/readwrite/model/BACnetClosingTag.go   |   178 +
 .../model/BACnetConfirmedServiceChoice.go          |   362 +
 .../model/BACnetConfirmedServiceRequest.go         |   261 +
 ...ACnetConfirmedServiceRequestAcknowledgeAlarm.go |   390 +
 .../BACnetConfirmedServiceRequestAddListElement.go |   345 +
 .../BACnetConfirmedServiceRequestAtomicReadFile.go |   242 +
 ...tConfirmedServiceRequestAtomicReadFileRecord.go |   238 +
 ...tConfirmedServiceRequestAtomicReadFileStream.go |   238 +
 ...edServiceRequestAtomicReadFileStreamOrRecord.go |   288 +
 ...BACnetConfirmedServiceRequestAtomicWriteFile.go |   382 +
 .../BACnetConfirmedServiceRequestAuthenticate.go   |   162 +
 ...firmedServiceRequestConfirmedCOVNotification.go |   353 +
 ...rviceRequestConfirmedCOVNotificationMultiple.go |   368 +
 ...rmedServiceRequestConfirmedEventNotification.go |   706 +
 ...firmedServiceRequestConfirmedPrivateTransfer.go |   294 +
 ...tConfirmedServiceRequestConfirmedTextMessage.go |   162 +
 ...ACnetConfirmedServiceRequestConfirmedUnknown.go |   197 +
 .../BACnetConfirmedServiceRequestCreateObject.go   |   257 +
 ...medServiceRequestCreateObjectObjectSpecifier.go |   374 +
 .../BACnetConfirmedServiceRequestDeleteObject.go   |   205 +
 ...rmedServiceRequestDeviceCommunicationControl.go |   308 +
 ...tConfirmedServiceRequestGetEnrollmentSummary.go |   162 +
 ...etConfirmedServiceRequestGetEventInformation.go |   220 +
 ...etConfirmedServiceRequestLifeSafetyOperation.go |   162 +
 .../BACnetConfirmedServiceRequestReadProperty.go   |   294 +
 ...nfirmedServiceRequestReadPropertyConditional.go |   162 +
 ...tConfirmedServiceRequestReadPropertyMultiple.go |   221 +
 .../BACnetConfirmedServiceRequestReadRange.go      |   345 +
 .../BACnetConfirmedServiceRequestReadRangeRange.go |   290 +
 ...firmedServiceRequestReadRangeRangeByPosition.go |   238 +
 ...ServiceRequestReadRangeRangeBySequenceNumber.go |   238 +
 ...tConfirmedServiceRequestReadRangeRangeByTime.go |   238 +
 ...netConfirmedServiceRequestReinitializeDevice.go |   257 +
 ...erviceRequestReinitializeDeviceEnableDisable.go |   130 +
 ...RequestReinitializeDeviceEnableDisableTagged.go |   197 +
 ...ReinitializeDeviceReinitializedStateOfDevice.go |   178 +
 ...ializeDeviceReinitializedStateOfDeviceTagged.go |   197 +
 ...CnetConfirmedServiceRequestRemoveListElement.go |   345 +
 .../BACnetConfirmedServiceRequestRequestKey.go     |   162 +
 .../BACnetConfirmedServiceRequestSubscribeCOV.go   |   345 +
 ...tConfirmedServiceRequestSubscribeCOVProperty.go |   433 +
 ...edServiceRequestSubscribeCOVPropertyMultiple.go |   396 +
 ...yMultipleListOfCovSubscriptionSpecifications.go |   280 +
 ...tipleListOfCovSubscriptionSpecificationsList.go |   248 +
 ...ListOfCovSubscriptionSpecificationsReference.go |   245 +
 .../model/BACnetConfirmedServiceRequestVTClose.go  |   162 +
 .../model/BACnetConfirmedServiceRequestVTData.go   |   162 +
 .../model/BACnetConfirmedServiceRequestVTOpen.go   |   162 +
 .../BACnetConfirmedServiceRequestWriteProperty.go  |   382 +
 ...ConfirmedServiceRequestWritePropertyMultiple.go |   221 +
 .../readwrite/model/BACnetConstructedData.go       |   276 +
 .../model/BACnetConstructedDataAcceptedModes.go    |   226 +
 .../readwrite/model/BACnetConstructedDataAction.go |   226 +
 .../model/BACnetConstructedDataElement.go          |   403 +
 .../model/BACnetConstructedDataEventTimestamps.go  |   285 +
 .../BACnetConstructedDataLifeSafetyAlarmValues.go  |   226 +
 ...netConstructedDataLifeSafetyPointAlarmValues.go |   226 +
 ...netConstructedDataLifeSafetyPointFaultValues.go |   226 +
 ...onstructedDataListOfObjectPropertyReferences.go |   226 +
 .../model/BACnetConstructedDataLoopAction.go       |   211 +
 .../model/BACnetConstructedDataMemberOf.go         |   226 +
 .../model/BACnetConstructedDataReliability.go      |   211 +
 .../model/BACnetConstructedDataSubordinateList.go  |   226 +
 .../model/BACnetConstructedDataUnspecified.go      |   226 +
 .../model/BACnetConstructedDataZoneMembers.go      |   226 +
 .../bacnetip/readwrite/model/BACnetContextTag.go   |   299 +
 .../readwrite/model/BACnetContextTagBitString.go   |   206 +
 .../readwrite/model/BACnetContextTagBoolean.go     |   263 +
 .../model/BACnetContextTagCharacterString.go       |   232 +
 .../readwrite/model/BACnetContextTagDate.go        |   206 +
 .../readwrite/model/BACnetContextTagDouble.go      |   232 +
 .../readwrite/model/BACnetContextTagEnumerated.go  |   232 +
 .../readwrite/model/BACnetContextTagNull.go        |   163 +
 .../model/BACnetContextTagObjectIdentifier.go      |   249 +
 .../readwrite/model/BACnetContextTagOctetString.go |   232 +
 .../readwrite/model/BACnetContextTagReal.go        |   232 +
 .../model/BACnetContextTagSignedInteger.go         |   232 +
 .../readwrite/model/BACnetContextTagTime.go        |   206 +
 .../readwrite/model/BACnetContextTagUnknown.go     |   199 +
 .../model/BACnetContextTagUnsignedInteger.go       |   232 +
 .../bacnetip/readwrite/model/BACnetDataType.go     |   218 +
 .../bacnetip/readwrite/model/BACnetDateTime.go     |   195 +
 .../readwrite/model/BACnetDateTimeEnclosed.go      |   233 +
 .../model/BACnetDeviceObjectPropertyReference.go   |   294 +
 .../BACnetDeviceObjectPropertyReferenceEnclosed.go |   233 +
 .../readwrite/model/BACnetDeviceObjectReference.go |   210 +
 .../bacnetip/readwrite/model/BACnetDeviceStatus.go |   162 +
 .../readwrite/model/BACnetDeviceStatusTagged.go    |   246 +
 .../readwrite/model/BACnetDoorAlarmState.go        |   186 +
 .../readwrite/model/BACnetDoorAlarmStateTagged.go  |   246 +
 .../readwrite/model/BACnetDoorSecuredStatus.go     |   130 +
 .../model/BACnetDoorSecuredStatusTagged.go         |   197 +
 .../bacnetip/readwrite/model/BACnetDoorStatus.go   |   194 +
 .../readwrite/model/BACnetDoorStatusTagged.go      |   246 +
 .../bacnetip/readwrite/model/BACnetDoorValue.go    |   138 +
 .../readwrite/model/BACnetDoorValueTagged.go       |   197 +
 .../readwrite/model/BACnetEngineeringUnits.go      |  2122 ++
 .../model/BACnetEngineeringUnitsTagged.go          |   246 +
 .../bacnetip/readwrite/model/BACnetError.go        |   181 +
 .../bacnetip/readwrite/model/BACnetErrorGeneral.go |   201 +
 .../readwrite/model/BACnetEscalatorFault.go        |   186 +
 .../readwrite/model/BACnetEscalatorFaultTagged.go  |   246 +
 .../readwrite/model/BACnetEscalatorMode.go         |   162 +
 .../readwrite/model/BACnetEscalatorModeTagged.go   |   246 +
 .../model/BACnetEscalatorOperationDirection.go     |   162 +
 .../BACnetEscalatorOperationDirectionTagged.go     |   246 +
 .../readwrite/model/BACnetEventProrities.go        |   303 +
 .../bacnetip/readwrite/model/BACnetEventState.go   |   162 +
 .../readwrite/model/BACnetEventStateTagged.go      |   246 +
 .../readwrite/model/BACnetEventSummariesList.go    |   248 +
 .../bacnetip/readwrite/model/BACnetEventSummary.go |   370 +
 .../readwrite/model/BACnetEventTimestamps.go       |   303 +
 .../readwrite/model/BACnetEventTransitionBits.go   |   223 +
 .../bacnetip/readwrite/model/BACnetEventType.go    |   274 +
 .../readwrite/model/BACnetEventTypeTagged.go       |   246 +
 .../bacnetip/readwrite/model/BACnetFaultType.go    |   170 +
 .../readwrite/model/BACnetFaultTypeTagged.go       |   197 +
 .../readwrite/model/BACnetFileAccessMethod.go      |   122 +
 .../model/BACnetFileAccessMethodTagged.go          |   197 +
 .../bacnetip/readwrite/model/BACnetIPMode.go       |   130 +
 .../bacnetip/readwrite/model/BACnetIPModeTagged.go |   197 +
 .../readwrite/model/BACnetLifeSafetyMode.go        |   234 +
 .../readwrite/model/BACnetLifeSafetyModeTagged.go  |   246 +
 .../readwrite/model/BACnetLifeSafetyOperation.go   |   194 +
 .../model/BACnetLifeSafetyOperationTagged.go       |   246 +
 .../readwrite/model/BACnetLifeSafetyState.go       |   306 +
 .../readwrite/model/BACnetLifeSafetyStateTagged.go |   246 +
 .../readwrite/model/BACnetLiftCarDirection.go      |   162 +
 .../model/BACnetLiftCarDirectionTagged.go          |   246 +
 .../readwrite/model/BACnetLiftCarDoorCommand.go    |   130 +
 .../model/BACnetLiftCarDoorCommandTagged.go        |   197 +
 .../readwrite/model/BACnetLiftCarDriveStatus.go    |   194 +
 .../model/BACnetLiftCarDriveStatusTagged.go        |   246 +
 .../bacnetip/readwrite/model/BACnetLiftCarMode.go  |   226 +
 .../readwrite/model/BACnetLiftCarModeTagged.go     |   246 +
 .../bacnetip/readwrite/model/BACnetLiftFault.go    |   250 +
 .../readwrite/model/BACnetLiftFaultTagged.go       |   246 +
 .../readwrite/model/BACnetLiftGroupMode.go         |   162 +
 .../readwrite/model/BACnetLiftGroupModeTagged.go   |   197 +
 .../readwrite/model/BACnetLightingInProgress.go    |   146 +
 .../model/BACnetLightingInProgressTagged.go        |   197 +
 .../readwrite/model/BACnetLightingOperation.go     |   202 +
 .../model/BACnetLightingOperationTagged.go         |   246 +
 .../readwrite/model/BACnetLightingTransition.go    |   138 +
 .../model/BACnetLightingTransitionTagged.go        |   246 +
 .../bacnetip/readwrite/model/BACnetLockStatus.go   |   146 +
 .../readwrite/model/BACnetLockStatusTagged.go      |   197 +
 .../bacnetip/readwrite/model/BACnetLoggingType.go  |   138 +
 .../readwrite/model/BACnetLoggingTypeTagged.go     |   246 +
 .../bacnetip/readwrite/model/BACnetMaintenance.go  |   146 +
 .../readwrite/model/BACnetMaintenanceTagged.go     |   246 +
 .../readwrite/model/BACnetNetworkNumberQuality.go  |   138 +
 .../model/BACnetNetworkNumberQualityTagged.go      |   197 +
 .../readwrite/model/BACnetNetworkPortCommand.go    |   178 +
 .../model/BACnetNetworkPortCommandTagged.go        |   246 +
 .../bacnetip/readwrite/model/BACnetNetworkType.go  |   202 +
 .../readwrite/model/BACnetNetworkTypeTagged.go     |   246 +
 .../bacnetip/readwrite/model/BACnetNodeType.go     |   282 +
 .../readwrite/model/BACnetNodeTypeTagged.go        |   197 +
 .../model/BACnetNotificationParameters.go          |   310 +
 .../BACnetNotificationParametersBufferReady.go     |   353 +
 ...ACnetNotificationParametersChangeOfBitString.go |   316 +
 .../BACnetNotificationParametersChangeOfState.go   |   316 +
 .../BACnetNotificationParametersChangeOfValue.go   |   316 +
 ...tNotificationParametersChangeOfValueNewValue.go |   291 +
 ...onParametersChangeOfValueNewValueChangedBits.go |   204 +
 ...nParametersChangeOfValueNewValueChangedValue.go |   204 +
 .../BACnetNotificationParametersCommandFailure.go  |   353 +
 ...BACnetNotificationParametersComplexEventType.go |   205 +
 .../model/BACnetNotificationParametersExtended.go  |   353 +
 ...CnetNotificationParametersExtendedParameters.go |  1044 +
 .../BACnetNotificationParametersFloatingLimit.go   |   390 +
 .../BACnetNotificationParametersOutOfRange.go      |   390 +
 .../model/BACnetNotificationParametersUnmapped.go  |   162 +
 .../BACnetNotificationParametersUnsignedRange.go   |   353 +
 .../bacnetip/readwrite/model/BACnetNotifyType.go   |   130 +
 .../readwrite/model/BACnetNotifyTypeTagged.go      |   197 +
 .../model/BACnetObjectPropertyReference.go         |   245 +
 .../model/BACnetObjectPropertyReferenceEnclosed.go |   233 +
 .../bacnetip/readwrite/model/BACnetObjectType.go   |   594 +
 .../readwrite/model/BACnetObjectTypeTagged.go      |   246 +
 .../bacnetip/readwrite/model/BACnetOpeningTag.go   |   178 +
 .../bacnetip/readwrite/model/BACnetPolarity.go     |   122 +
 .../readwrite/model/BACnetPolarityTagged.go        |   197 +
 .../bacnetip/readwrite/model/BACnetProgramError.go |   154 +
 .../readwrite/model/BACnetProgramErrorTagged.go    |   246 +
 .../readwrite/model/BACnetProgramRequest.go        |   154 +
 .../readwrite/model/BACnetProgramRequestTagged.go  |   197 +
 .../bacnetip/readwrite/model/BACnetProgramState.go |   154 +
 .../readwrite/model/BACnetProgramStateTagged.go    |   197 +
 .../readwrite/model/BACnetPropertyIdentifier.go    |  3770 +++
 .../model/BACnetPropertyIdentifierTagged.go        |   246 +
 .../readwrite/model/BACnetPropertyReference.go     |   210 +
 .../model/BACnetPropertyReferenceEnclosed.go       |   233 +
 .../model/BACnetPropertyStateActionUnmapped.go     |   161 +
 .../readwrite/model/BACnetPropertyStates.go        |   299 +
 .../readwrite/model/BACnetPropertyStatesAction.go  |   204 +
 .../model/BACnetPropertyStatesBinaryValue.go       |   204 +
 .../readwrite/model/BACnetPropertyStatesBoolean.go |   204 +
 .../model/BACnetPropertyStatesNetworkType.go       |   204 +
 .../model/BACnetPropertyStatesReliability.go       |   204 +
 .../readwrite/model/BACnetPropertyValue.go         |   311 +
 .../readwrite/model/BACnetPropertyValues.go        |   249 +
 .../model/BACnetPropertyWriteDefinition.go         |   311 +
 .../readwrite/model/BACnetProtocolLevel.go         |   138 +
 .../readwrite/model/BACnetProtocolLevelTagged.go   |   197 +
 .../readwrite/model/BACnetReadAccessProperty.go    |   262 +
 .../model/BACnetReadAccessPropertyReadResult.go    |   288 +
 .../readwrite/model/BACnetReadAccessResult.go      |   210 +
 .../model/BACnetReadAccessResultListOfResults.go   |   249 +
 .../model/BACnetReadAccessSpecification.go         |   280 +
 .../bacnetip/readwrite/model/BACnetRejectReason.go |   194 +
 .../readwrite/model/BACnetRejectReasonTagged.go    |   200 +
 .../bacnetip/readwrite/model/BACnetRelationship.go |   354 +
 .../readwrite/model/BACnetRelationshipTagged.go    |   246 +
 .../bacnetip/readwrite/model/BACnetReliability.go  |   306 +
 .../readwrite/model/BACnetReliabilityTagged.go     |   246 +
 .../readwrite/model/BACnetRestartReason.go         |   186 +
 .../readwrite/model/BACnetRestartReasonTagged.go   |   246 +
 .../bacnetip/readwrite/model/BACnetResultFlags.go  |   223 +
 .../readwrite/model/BACnetSecurityLevel.go         |   154 +
 .../readwrite/model/BACnetSecurityLevelTagged.go   |   197 +
 .../readwrite/model/BACnetSecurityPolicy.go        |   138 +
 .../readwrite/model/BACnetSecurityPolicyTagged.go  |   197 +
 .../bacnetip/readwrite/model/BACnetSegmentation.go |   138 +
 .../readwrite/model/BACnetSegmentationTagged.go    |   197 +
 .../bacnetip/readwrite/model/BACnetServiceAck.go   |   259 +
 .../model/BACnetServiceAckAcknowledgeAlarm.go      |   161 +
 .../model/BACnetServiceAckAddListElement.go        |   161 +
 .../model/BACnetServiceAckAtomicReadFile.go        |   241 +
 .../model/BACnetServiceAckAtomicReadFileRecord.go  |   290 +
 .../model/BACnetServiceAckAtomicReadFileStream.go  |   238 +
 ...BACnetServiceAckAtomicReadFileStreamOrRecord.go |   288 +
 .../model/BACnetServiceAckAtomicWriteFile.go       |   204 +
 .../model/BACnetServiceAckAuthenticate.go          |   161 +
 .../BACnetServiceAckConfirmedCovNotification.go    |   161 +
 ...etServiceAckConfirmedCovNotificationMultiple.go |   162 +
 .../BACnetServiceAckConfirmedEventNotification.go  |   161 +
 .../BACnetServiceAckConfirmedPrivateTransfer.go    |   293 +
 .../model/BACnetServiceAckConfirmedTextMessage.go  |   161 +
 .../model/BACnetServiceAckCreateObject.go          |   161 +
 .../BACnetServiceAckDeviceCommunicationControl.go  |   161 +
 .../model/BACnetServiceAckGetAlarmSummary.go       |   161 +
 .../model/BACnetServiceAckGetEnrollmentSummary.go  |   161 +
 .../model/BACnetServiceAckGetEventInformation.go   |   241 +
 .../model/BACnetServiceAckLifeSafetyOperation.go   |   161 +
 .../model/BACnetServiceAckReadProperty.go          |   344 +
 .../BACnetServiceAckReadPropertyConditional.go     |   161 +
 .../model/BACnetServiceAckReadPropertyMultiple.go  |   220 +
 .../readwrite/model/BACnetServiceAckReadRange.go   |   469 +
 .../model/BACnetServiceAckReinitializeDevice.go    |   161 +
 .../model/BACnetServiceAckRemoveListElement.go     |   161 +
 .../readwrite/model/BACnetServiceAckRequestKey.go  |   161 +
 .../model/BACnetServiceAckSubscribeCov.go          |   161 +
 .../model/BACnetServiceAckSubscribeCovProperty.go  |   161 +
 ...BACnetServiceAckSubscribeCovPropertyMultiple.go |   161 +
 .../readwrite/model/BACnetServiceAckVTClose.go     |   161 +
 .../readwrite/model/BACnetServiceAckVTData.go      |   161 +
 .../readwrite/model/BACnetServiceAckVTOpen.go      |   161 +
 .../model/BACnetServiceAckWriteProperty.go         |   161 +
 .../model/BACnetServiceAckWritePropertyMultiple.go |   161 +
 .../bacnetip/readwrite/model/BACnetShedState.go    |   138 +
 .../readwrite/model/BACnetShedStateTagged.go       |   197 +
 .../readwrite/model/BACnetSilencedState.go         |   146 +
 .../readwrite/model/BACnetSilencedStateTagged.go   |   246 +
 .../bacnetip/readwrite/model/BACnetStatusFlags.go  |   240 +
 .../bacnetip/readwrite/model/BACnetTagHeader.go    |   478 +
 .../readwrite/model/BACnetTagPayloadBitString.go   |   246 +
 .../readwrite/model/BACnetTagPayloadBoolean.go     |   179 +
 .../model/BACnetTagPayloadCharacterString.go       |   213 +
 .../readwrite/model/BACnetTagPayloadDate.go        |   417 +
 .../readwrite/model/BACnetTagPayloadDouble.go      |   149 +
 .../readwrite/model/BACnetTagPayloadEnumerated.go  |   181 +
 .../model/BACnetTagPayloadObjectIdentifier.go      |   221 +
 .../readwrite/model/BACnetTagPayloadOctetString.go |   178 +
 .../readwrite/model/BACnetTagPayloadReal.go        |   149 +
 .../model/BACnetTagPayloadSignedInteger.go         |   719 +
 .../readwrite/model/BACnetTagPayloadTime.go        |   315 +
 .../model/BACnetTagPayloadUnsignedInteger.go       |   719 +
 .../bacnetip/readwrite/model/BACnetTimeStamp.go    |   220 +
 .../readwrite/model/BACnetTimeStampDateTime.go     |   199 +
 .../readwrite/model/BACnetTimeStampEnclosed.go     |   233 +
 .../readwrite/model/BACnetTimeStampSequence.go     |   199 +
 .../readwrite/model/BACnetTimeStampTime.go         |   199 +
 .../readwrite/model/BACnetTimeStampsEnclosed.go    |   248 +
 .../bacnetip/readwrite/model/BACnetTimerState.go   |   130 +
 .../readwrite/model/BACnetTimerStateTagged.go      |   197 +
 .../readwrite/model/BACnetTimerTransition.go       |   170 +
 .../readwrite/model/BACnetTimerTransitionTagged.go |   197 +
 .../model/BACnetUnconfirmedServiceChoice.go        |   202 +
 .../model/BACnetUnconfirmedServiceChoiceTagged.go  |   197 +
 .../model/BACnetUnconfirmedServiceRequest.go       |   223 +
 .../model/BACnetUnconfirmedServiceRequestIAm.go    |   316 +
 .../model/BACnetUnconfirmedServiceRequestIHave.go  |   279 +
 ...UnconfirmedServiceRequestTimeSynchronization.go |   242 +
 ...onfirmedServiceRequestUTCTimeSynchronization.go |   242 +
 ...rmedServiceRequestUnconfirmedCOVNotification.go |   353 +
 ...iceRequestUnconfirmedCOVNotificationMultiple.go |   368 +
 ...edServiceRequestUnconfirmedEventNotification.go |   706 +
 ...rmedServiceRequestUnconfirmedPrivateTransfer.go |   294 +
 ...onfirmedServiceRequestUnconfirmedTextMessage.go |   162 +
 ...tUnconfirmedServiceRequestUnconfirmedUnknown.go |   197 +
 .../model/BACnetUnconfirmedServiceRequestWhoHas.go |   373 +
 .../model/BACnetUnconfirmedServiceRequestWhoIs.go  |   271 +
 .../BACnetUnconfirmedServiceRequestWriteGroup.go   |   162 +
 .../bacnetip/readwrite/model/BACnetVTClass.go      |   170 +
 .../readwrite/model/BACnetVTClassTagged.go         |   246 +
 .../bacnetip/readwrite/model/BACnetVendorId.go     | 21775 ++++++++++++++++++
 .../model/BACnetWriteAccessSpecification.go        |   280 +
 .../bacnetip/readwrite/model/BACnetWriteStatus.go  |   138 +
 .../readwrite/model/BACnetWriteStatusTagged.go     |   197 +
 plc4go/protocols/bacnetip/readwrite/model/BVLC.go  |   286 +
 .../model/BVLCBroadcastDistributionTableEntry.go   |   243 +
 .../model/BVLCDeleteForeignDeviceTableEntry.go     |   239 +
 .../model/BVLCDistributeBroadcastToNetwork.go      |   204 +
 .../readwrite/model/BVLCForeignDeviceTableEntry.go |   244 +
 .../bacnetip/readwrite/model/BVLCForwardedNPDU.go  |   279 +
 .../readwrite/model/BVLCOriginalBroadcastNPDU.go   |   204 +
 .../readwrite/model/BVLCOriginalUnicastNPDU.go     |   204 +
 .../model/BVLCReadBroadcastDistributionTable.go    |   153 +
 .../model/BVLCReadBroadcastDistributionTableAck.go |   220 +
 .../readwrite/model/BVLCReadForeignDeviceTable.go  |   153 +
 .../model/BVLCReadForeignDeviceTableAck.go         |   220 +
 .../readwrite/model/BVLCRegisterForeignDevice.go   |   190 +
 .../bacnetip/readwrite/model/BVLCResult.go         |   201 +
 .../bacnetip/readwrite/model/BVLCResultCode.go     |   162 +
 .../readwrite/model/BVLCResultCodeTagged.go        |   197 +
 .../bacnetip/readwrite/model/BVLCSecureBVLL.go     |   196 +
 .../model/BVLCWriteBroadcastDistributionTable.go   |   220 +
 .../bacnetip/readwrite/model/ChangeListAddError.go |   238 +
 .../readwrite/model/ChangeListRemoveError.go       |   238 +
 .../model/ConfirmedPrivateTransferError.go         |   327 +
 .../bacnetip/readwrite/model/CreateObjectError.go  |   238 +
 plc4go/protocols/bacnetip/readwrite/model/Error.go |   195 +
 .../bacnetip/readwrite/model/ErrorClass.go         |   178 +
 .../bacnetip/readwrite/model/ErrorClassTagged.go   |   246 +
 .../bacnetip/readwrite/model/ErrorCode.go          |  1146 +
 .../bacnetip/readwrite/model/ErrorCodeTagged.go    |   246 +
 .../bacnetip/readwrite/model/ErrorEnclosed.go      |   233 +
 .../readwrite/model/ListOfCovNotifications.go      |   280 +
 .../readwrite/model/ListOfCovNotificationsList.go  |   248 +
 .../readwrite/model/ListOfCovNotificationsValue.go |   297 +
 .../readwrite/model/MaxApduLengthAccepted.go       |   234 +
 .../readwrite/model/MaxApduLengthAcceptedTagged.go |   197 +
 .../readwrite/model/MaxSegmentsAccepted.go         |   170 +
 .../readwrite/model/MaxSegmentsAcceptedTagged.go   |   197 +
 plc4go/protocols/bacnetip/readwrite/model/NLM.go   |   246 +
 .../model/NLMDisconnectConnectionToNetwork.go      |   195 +
 .../model/NLMEstablishConnectionToNetwork.go       |   221 +
 .../readwrite/model/NLMIAmRouterToNetwork.go       |   220 +
 .../readwrite/model/NLMICouldBeRouterToNetwork.go  |   221 +
 .../readwrite/model/NLMInitalizeRoutingTable.go    |   247 +
 .../readwrite/model/NLMInitalizeRoutingTableAck.go |   247 +
 .../model/NLMInitalizeRoutingTablePortMapping.go   |   224 +
 .../readwrite/model/NLMRejectRouterToNetwork.go    |   232 +
 .../model/NLMRejectRouterToNetworkRejectReason.go  |   162 +
 .../readwrite/model/NLMRouterAvailableToNetwork.go |   220 +
 .../readwrite/model/NLMRouterBusyToNetwork.go      |   220 +
 .../readwrite/model/NLMWhoIsRouterToNetwork.go     |   220 +
 plc4go/protocols/bacnetip/readwrite/model/NPDU.go  |   647 +
 .../bacnetip/readwrite/model/NPDUControl.go        |   307 +
 .../readwrite/model/NPDUNetworkPriority.go         |   138 +
 .../readwrite/model/NPDUNetworkPriorityTagged.go   |   197 +
 .../bacnetip/readwrite/model/StaticHelper.go       |   618 +
 .../model/SubscribeCOVPropertyMultipleError.go     |   238 +
 ...PropertyMultipleErrorFirstFailedSubscription.go |   303 +
 .../protocols/bacnetip/readwrite/model/TagClass.go |   122 +
 .../bacnetip/readwrite/model/VTCloseError.go       |   253 +
 .../VTCloseErrorListOfVTSessionIdentifiers.go      |   248 +
 .../readwrite/model/WritePropertyMultipleError.go  |   238 +
 plc4go/protocols/cbus/readwrite/ParserHelper.go    |   120 +
 plc4go/protocols/cbus/readwrite/XmlParserHelper.go |   118 +
 plc4go/protocols/cbus/readwrite/model/Alpha.go     |   149 +
 .../cbus/readwrite/model/ApplicationId.go          |   266 +
 .../cbus/readwrite/model/ApplicationIdContainer.go |  4239 ++++
 plc4go/protocols/cbus/readwrite/model/Attribute.go |   340 +
 .../cbus/readwrite/model/BridgeAddress.go          |   149 +
 .../protocols/cbus/readwrite/model/BridgeCount.go  |   149 +
 .../cbus/readwrite/model/CALCommandType.go         |   158 +
 .../readwrite/model/CALCommandTypeContainer.go     |  1697 ++
 plc4go/protocols/cbus/readwrite/model/CALData.go   |   250 +
 .../readwrite/model/CALDataReplyAcknowledge.go     |   214 +
 .../cbus/readwrite/model/CALDataReplyReply.go      |   217 +
 .../cbus/readwrite/model/CALDataReplyStatus.go     |   254 +
 .../readwrite/model/CALDataReplyStatusExtended.go  |   280 +
 .../readwrite/model/CALDataRequestGetStatus.go     |   214 +
 .../cbus/readwrite/model/CALDataRequestIdentify.go |   199 +
 .../cbus/readwrite/model/CALDataRequestRecall.go   |   214 +
 .../cbus/readwrite/model/CALDataRequestReset.go    |   151 +
 plc4go/protocols/cbus/readwrite/model/CALReply.go  |   286 +
 .../protocols/cbus/readwrite/model/CALReplyLong.go |   471 +
 .../cbus/readwrite/model/CALReplyReply.go          |   199 +
 .../cbus/readwrite/model/CALReplyShort.go          |   152 +
 .../protocols/cbus/readwrite/model/CBusCommand.go  |   278 +
 .../model/CBusCommandPointToMultiPoint.go          |   202 +
 .../readwrite/model/CBusCommandPointToPoint.go     |   202 +
 .../model/CBusCommandPointToPointToMultiPoint.go   |   202 +
 .../CBusCommandPointToPointToMultiPointNormal.go   |   397 +
 .../CBusCommandPointToPointToMultiPointStatus.go   |   386 +
 .../protocols/cbus/readwrite/model/CBusHeader.go   |   246 +
 .../protocols/cbus/readwrite/model/CBusOptions.go  |   317 +
 .../model/CBusPointToMultiPointCommand.go          |   196 +
 .../model/CBusPointToMultiPointCommandNormal.go    |   421 +
 .../model/CBusPointToMultiPointCommandStatus.go    |   409 +
 .../readwrite/model/CBusPointToPointCommand.go     |   411 +
 .../model/CBusPointToPointCommandDirect.go         |   232 +
 .../model/CBusPointToPointCommandIndirect.go       |   280 +
 .../model/CBusPointToPointToMultipointCommand.go   |   266 +
 .../cbus/readwrite/model/ChannelStatus.go          |   130 +
 plc4go/protocols/cbus/readwrite/model/Checksum.go  |   149 +
 .../cbus/readwrite/model/CommandHeader.go          |   149 +
 .../protocols/cbus/readwrite/model/Confirmation.go |   236 +
 .../cbus/readwrite/model/ConfirmationReply.go      |   199 +
 .../cbus/readwrite/model/ConfirmationSuccessful.go |   155 +
 .../cbus/readwrite/model/DestinationAddressType.go |   130 +
 .../cbus/readwrite/model/ExclamationMark.go        |   114 +
 .../cbus/readwrite/model/ExclamationMarkReply.go   |   199 +
 .../readwrite/model/ExtendedFormatStatusReply.go   |   397 +
 .../cbus/readwrite/model/ExtendedStatusHeader.go   |   175 +
 plc4go/protocols/cbus/readwrite/model/GAVState.go  |   138 +
 .../cbus/readwrite/model/IdentifyReplyCommand.go   |   201 +
 .../IdentifyReplyCommandCurrentSenseLevels.go      |   153 +
 .../model/IdentifyReplyCommandDSIStatus.go         |   523 +
 .../readwrite/model/IdentifyReplyCommandDelays.go  |   153 +
 ...dentifyReplyCommandExtendedDiagnosticSummary.go |   757 +
 .../model/IdentifyReplyCommandFirmwareSummary.go   |   242 +
 .../model/IdentifyReplyCommandFirmwareVersion.go   |   190 +
 .../IdentifyReplyCommandGAVPhysicalAddresses.go    |   193 +
 .../model/IdentifyReplyCommandGAVValuesCurrent.go  |   193 +
 .../model/IdentifyReplyCommandGAVValuesStored.go   |   193 +
 .../model/IdentifyReplyCommandLogicalAssignment.go |   153 +
 .../model/IdentifyReplyCommandManufacturer.go      |   190 +
 .../model/IdentifyReplyCommandMaximumLevels.go     |   153 +
 .../model/IdentifyReplyCommandMinimumLevels.go     |   153 +
 .../IdentifyReplyCommandNetworkTerminalLevels.go   |   153 +
 .../model/IdentifyReplyCommandNetworkVoltage.go    |   274 +
 .../model/IdentifyReplyCommandOutputUnitSummary.go |   153 +
 .../model/IdentifyReplyCommandTerminalLevels.go    |   153 +
 .../readwrite/model/IdentifyReplyCommandType.go    |   190 +
 .../cbus/readwrite/model/LightingCompatible.go     |   138 +
 .../protocols/cbus/readwrite/model/MonitoredSAL.go |   301 +
 .../model/MonitoredSALLongFormSmartMode.go         |   471 +
 .../cbus/readwrite/model/MonitoredSALReply.go      |   199 +
 .../model/MonitoredSALShortFormBasicMode.go        |   355 +
 .../cbus/readwrite/model/NetworkNumber.go          |   149 +
 .../model/NetworkProtocolControlInformation.go     |   199 +
 .../protocols/cbus/readwrite/model/NetworkRoute.go |   210 +
 .../readwrite/model/NotTransmittedCorruption.go    |   155 +
 .../cbus/readwrite/model/NotTransmittedSyncLoss.go |   155 +
 .../model/NotTransmittedToManyReTransmissions.go   |   155 +
 .../cbus/readwrite/model/NotTransmittedTooLong.go  |   155 +
 .../cbus/readwrite/model/ParameterChange.go        |   220 +
 .../cbus/readwrite/model/ParameterChangeReply.go   |   199 +
 plc4go/protocols/cbus/readwrite/model/PowerUp.go   |   197 +
 .../protocols/cbus/readwrite/model/PowerUpReply.go |   199 +
 .../cbus/readwrite/model/PriorityClass.go          |   138 +
 plc4go/protocols/cbus/readwrite/model/Reply.go     |   201 +
 .../protocols/cbus/readwrite/model/ReplyNetwork.go |   245 +
 plc4go/protocols/cbus/readwrite/model/RouteType.go |   208 +
 .../cbus/readwrite/model/SALCommandType.go         |   138 +
 .../readwrite/model/SALCommandTypeContainer.go     |   352 +
 plc4go/protocols/cbus/readwrite/model/SALData.go   |   242 +
 .../protocols/cbus/readwrite/model/SALDataOff.go   |   188 +
 plc4go/protocols/cbus/readwrite/model/SALDataOn.go |   188 +
 .../cbus/readwrite/model/SALDataRampToLevel.go     |   214 +
 .../cbus/readwrite/model/SALDataTerminateRamp.go   |   188 +
 .../cbus/readwrite/model/SerialInterfaceAddress.go |   149 +
 .../readwrite/model/StandardFormatStatusReply.go   |   362 +
 .../protocols/cbus/readwrite/model/StatusByte.go   |   265 +
 .../protocols/cbus/readwrite/model/StatusCoding.go |   138 +
 .../protocols/cbus/readwrite/model/StatusHeader.go |   175 +
 .../cbus/readwrite/model/StatusRequest.go          |   193 +
 .../readwrite/model/StatusRequestBinaryState.go    |   239 +
 .../cbus/readwrite/model/StatusRequestLevel.go     |   270 +
 .../protocols/cbus/readwrite/model/UnitAddress.go  |   149 +
 .../protocols/cbus/readwrite/model/UnitStatus.go   |   130 +
 plc4go/protocols/df1/readwrite/ParserHelper.go     |    41 +
 plc4go/protocols/df1/readwrite/XmlParserHelper.go  |    51 +
 plc4go/protocols/df1/readwrite/model/DF1Command.go |   243 +
 plc4go/protocols/df1/readwrite/model/DF1Symbol.go  |   223 +
 .../df1/readwrite/model/DF1SymbolMessageFrame.go   |   341 +
 .../readwrite/model/DF1SymbolMessageFrameACK.go    |   153 +
 .../readwrite/model/DF1SymbolMessageFrameNAK.go    |   153 +
 .../readwrite/model/DF1UnprotectedReadRequest.go   |   219 +
 .../readwrite/model/DF1UnprotectedReadResponse.go  |   209 +
 .../protocols/df1/readwrite/model/StaticHelper.go  |    84 +
 .../df1/readwrite/model/StaticHelper_test.go       |     0
 plc4go/protocols/eip/readwrite/ParserHelper.go     |    57 +
 plc4go/protocols/eip/readwrite/XmlParserHelper.go  |    70 +
 .../eip/readwrite/model/CIPDataTypeCode.go         |   224 +
 .../protocols/eip/readwrite/model/CipExchange.go   |   261 +
 plc4go/protocols/eip/readwrite/model/CipRRData.go  |   260 +
 .../eip/readwrite/model/CipReadRequest.go          |   248 +
 .../eip/readwrite/model/CipReadResponse.go         |   311 +
 plc4go/protocols/eip/readwrite/model/CipService.go |   198 +
 .../eip/readwrite/model/CipUnconnectedRequest.go   |   459 +
 .../eip/readwrite/model/CipWriteRequest.go         |   314 +
 .../eip/readwrite/model/CipWriteResponse.go        |   245 +
 plc4go/protocols/eip/readwrite/model/EiPCommand.go |   130 +
 .../eip/readwrite/model/EipConnectionRequest.go    |   218 +
 .../eip/readwrite/model/EipDisconnectRequest.go    |   158 +
 plc4go/protocols/eip/readwrite/model/EipPacket.go  |   333 +
 .../eip/readwrite/model/MultipleServiceRequest.go  |   262 +
 .../eip/readwrite/model/MultipleServiceResponse.go |   349 +
 plc4go/protocols/eip/readwrite/model/Services.go   |   249 +
 plc4go/protocols/firmata/readwrite/ParserHelper.go |    55 +
 .../protocols/firmata/readwrite/XmlParserHelper.go |    56 +
 .../firmata/readwrite/model/FirmataCommand.go      |   194 +
 .../model/FirmataCommandProtocolVersion.go         |   219 +
 .../model/FirmataCommandSetDigitalPinValue.go      |   245 +
 .../readwrite/model/FirmataCommandSetPinMode.go    |   230 +
 .../firmata/readwrite/model/FirmataCommandSysex.go |   230 +
 .../readwrite/model/FirmataCommandSystemReset.go   |   156 +
 .../firmata/readwrite/model/FirmataMessage.go      |   194 +
 .../readwrite/model/FirmataMessageAnalogIO.go      |   242 +
 .../readwrite/model/FirmataMessageCommand.go       |   204 +
 .../readwrite/model/FirmataMessageDigitalIO.go     |   242 +
 .../model/FirmataMessageSubscribeAnalogPinValue.go |   245 +
 .../FirmataMessageSubscribeDigitalPinValue.go      |   245 +
 .../protocols/firmata/readwrite/model/PinMode.go   |   202 +
 .../firmata/readwrite/model/StaticHelper.go        |    45 +
 .../firmata/readwrite/model/SysexCommand.go        |   213 +
 .../model/SysexCommandAnalogMappingQueryRequest.go |   157 +
 .../SysexCommandAnalogMappingQueryResponse.go      |   194 +
 .../model/SysexCommandAnalogMappingResponse.go     |   157 +
 .../readwrite/model/SysexCommandCapabilityQuery.go |   157 +
 .../model/SysexCommandCapabilityResponse.go        |   157 +
 .../readwrite/model/SysexCommandExtendedAnalog.go  |   157 +
 .../readwrite/model/SysexCommandExtendedId.go      |   217 +
 .../readwrite/model/SysexCommandPinStateQuery.go   |   194 +
 .../model/SysexCommandPinStateResponse.go          |   246 +
 .../model/SysexCommandReportFirmwareRequest.go     |   157 +
 .../model/SysexCommandReportFirmwareResponse.go    |   263 +
 .../model/SysexCommandSamplingInterval.go          |   157 +
 .../readwrite/model/SysexCommandStringData.go      |   157 +
 .../model/SysexCommandSysexNonRealtime.go          |   157 +
 .../readwrite/model/SysexCommandSysexRealtime.go   |   157 +
 plc4go/protocols/init.go                           |    21 +
 .../protocols/knxnetip/readwrite/ParserHelper.go   |   138 +
 .../knxnetip/readwrite/XmlParserHelper.go          |   154 +
 .../knxnetip/readwrite/model/AccessLevel.go        |   223 +
 plc4go/protocols/knxnetip/readwrite/model/Apdu.go  |   246 +
 .../knxnetip/readwrite/model/ApduControl.go        |   189 +
 .../knxnetip/readwrite/model/ApduControlAck.go     |   153 +
 .../knxnetip/readwrite/model/ApduControlConnect.go |   153 +
 .../readwrite/model/ApduControlContainer.go        |   207 +
 .../readwrite/model/ApduControlDisconnect.go       |   153 +
 .../knxnetip/readwrite/model/ApduControlNack.go    |   153 +
 .../protocols/knxnetip/readwrite/model/ApduData.go |   216 +
 .../knxnetip/readwrite/model/ApduDataAdcRead.go    |   156 +
 .../readwrite/model/ApduDataAdcResponse.go         |   156 +
 .../knxnetip/readwrite/model/ApduDataContainer.go  |   207 +
 .../model/ApduDataDeviceDescriptorRead.go          |   193 +
 .../model/ApduDataDeviceDescriptorResponse.go      |   222 +
 .../knxnetip/readwrite/model/ApduDataExt.go        |   266 +
 .../readwrite/model/ApduDataExtAuthorizeRequest.go |   222 +
 .../model/ApduDataExtAuthorizeResponse.go          |   193 +
 .../model/ApduDataExtDomainAddressRead.go          |   156 +
 .../model/ApduDataExtDomainAddressResponse.go      |   156 +
 .../model/ApduDataExtDomainAddressSelectiveRead.go |   156 +
 .../ApduDataExtDomainAddressSerialNumberRead.go    |   156 +
 ...ApduDataExtDomainAddressSerialNumberResponse.go |   156 +
 .../ApduDataExtDomainAddressSerialNumberWrite.go   |   156 +
 .../model/ApduDataExtDomainAddressWrite.go         |   156 +
 .../model/ApduDataExtFileStreamInfoReport.go       |   156 +
 .../ApduDataExtGroupPropertyValueInfoReport.go     |   156 +
 .../model/ApduDataExtGroupPropertyValueRead.go     |   156 +
 .../model/ApduDataExtGroupPropertyValueResponse.go |   156 +
 .../model/ApduDataExtGroupPropertyValueWrite.go    |   156 +
 ...ApduDataExtIndividualAddressSerialNumberRead.go |   156 +
 ...DataExtIndividualAddressSerialNumberResponse.go |   156 +
 ...pduDataExtIndividualAddressSerialNumberWrite.go |   156 +
 .../readwrite/model/ApduDataExtKeyResponse.go      |   156 +
 .../readwrite/model/ApduDataExtKeyWrite.go         |   156 +
 .../readwrite/model/ApduDataExtLinkRead.go         |   156 +
 .../readwrite/model/ApduDataExtLinkResponse.go     |   156 +
 .../readwrite/model/ApduDataExtLinkWrite.go        |   156 +
 .../readwrite/model/ApduDataExtMemoryBitWrite.go   |   156 +
 .../model/ApduDataExtNetworkParameterRead.go       |   156 +
 .../model/ApduDataExtNetworkParameterResponse.go   |   156 +
 .../model/ApduDataExtNetworkParameterWrite.go      |   156 +
 .../model/ApduDataExtOpenRoutingTableRequest.go    |   156 +
 .../model/ApduDataExtPropertyDescriptionRead.go    |   245 +
 .../ApduDataExtPropertyDescriptionResponse.go      |   459 +
 .../model/ApduDataExtPropertyValueRead.go          |   271 +
 .../model/ApduDataExtPropertyValueResponse.go      |   300 +
 .../model/ApduDataExtPropertyValueWrite.go         |   300 +
 .../model/ApduDataExtReadRouterMemoryRequest.go    |   156 +
 .../model/ApduDataExtReadRouterMemoryResponse.go   |   156 +
 .../model/ApduDataExtReadRouterStatusRequest.go    |   156 +
 .../model/ApduDataExtReadRouterStatusResponse.go   |   156 +
 .../model/ApduDataExtReadRoutingTableRequest.go    |   156 +
 .../model/ApduDataExtReadRoutingTableResponse.go   |   156 +
 .../model/ApduDataExtWriteRouterMemoryRequest.go   |   156 +
 .../model/ApduDataExtWriteRouterStatusRequest.go   |   156 +
 .../model/ApduDataExtWriteRoutingTableRequest.go   |   156 +
 .../readwrite/model/ApduDataGroupValueRead.go      |   183 +
 .../readwrite/model/ApduDataGroupValueResponse.go  |   222 +
 .../readwrite/model/ApduDataGroupValueWrite.go     |   222 +
 .../model/ApduDataIndividualAddressRead.go         |   156 +
 .../model/ApduDataIndividualAddressResponse.go     |   156 +
 .../model/ApduDataIndividualAddressWrite.go        |   156 +
 .../knxnetip/readwrite/model/ApduDataMemoryRead.go |   219 +
 .../readwrite/model/ApduDataMemoryResponse.go      |   239 +
 .../readwrite/model/ApduDataMemoryWrite.go         |   156 +
 .../knxnetip/readwrite/model/ApduDataOther.go      |   204 +
 .../knxnetip/readwrite/model/ApduDataRestart.go    |   156 +
 .../readwrite/model/ApduDataUserMessage.go         |   156 +
 plc4go/protocols/knxnetip/readwrite/model/CEMI.go  |   230 +
 .../readwrite/model/CEMIAdditionalInformation.go   |   185 +
 .../CEMIAdditionalInformationBusmonitorInfo.go     |   356 +
 .../CEMIAdditionalInformationRelativeTimestamp.go  |   237 +
 .../knxnetip/readwrite/model/CEMIPriority.go       |   138 +
 .../knxnetip/readwrite/model/ChannelInformation.go |   173 +
 .../knxnetip/readwrite/model/ComObjectTable.go     |   171 +
 .../readwrite/model/ComObjectTableAddresses.go     | 22636 +++++++++++++++++++
 .../model/ComObjectTableRealisationType1.go        |   268 +
 .../model/ComObjectTableRealisationType2.go        |   268 +
 .../model/ComObjectTableRealisationType6.go        |   201 +
 .../knxnetip/readwrite/model/ComObjectValueType.go |   304 +
 .../knxnetip/readwrite/model/ConnectionRequest.go  |   275 +
 .../model/ConnectionRequestInformation.go          |   202 +
 ...ConnectionRequestInformationDeviceManagement.go |   154 +
 ...ConnectionRequestInformationTunnelConnection.go |   228 +
 .../knxnetip/readwrite/model/ConnectionResponse.go |   330 +
 .../readwrite/model/ConnectionResponseDataBlock.go |   202 +
 .../ConnectionResponseDataBlockDeviceManagement.go |   154 +
 .../ConnectionResponseDataBlockTunnelConnection.go |   202 +
 .../readwrite/model/ConnectionStateRequest.go      |   253 +
 .../readwrite/model/ConnectionStateResponse.go     |   227 +
 .../knxnetip/readwrite/model/DIBDeviceInfo.go      |   430 +
 .../knxnetip/readwrite/model/DIBSuppSvcFamilies.go |   217 +
 .../knxnetip/readwrite/model/DescriptionRequest.go |   201 +
 .../readwrite/model/DescriptionResponse.go         |   238 +
 .../readwrite/model/DeviceConfigurationAck.go      |   201 +
 .../model/DeviceConfigurationAckDataBlock.go       |   225 +
 .../readwrite/model/DeviceConfigurationRequest.go  |   241 +
 .../model/DeviceConfigurationRequestDataBlock.go   |   216 +
 .../knxnetip/readwrite/model/DeviceDescriptor.go   |   607 +
 .../readwrite/model/DeviceDescriptorMediumType.go  |   154 +
 .../readwrite/model/DeviceDescriptorType2.go       |   409 +
 .../knxnetip/readwrite/model/DeviceStatus.go       |   175 +
 .../knxnetip/readwrite/model/DisconnectRequest.go  |   253 +
 .../knxnetip/readwrite/model/DisconnectResponse.go |   227 +
 .../knxnetip/readwrite/model/FirmwareType.go       |   234 +
 .../model/GroupObjectDescriptorRealisationType1.go |   365 +
 .../model/GroupObjectDescriptorRealisationType2.go |   363 +
 .../model/GroupObjectDescriptorRealisationType6.go |   114 +
 .../model/GroupObjectDescriptorRealisationType7.go |   363 +
 .../model/GroupObjectDescriptorRealisationTypeB.go |   339 +
 .../readwrite/model/HPAIControlEndpoint.go         |   236 +
 .../knxnetip/readwrite/model/HPAIDataEndpoint.go   |   236 +
 .../readwrite/model/HPAIDiscoveryEndpoint.go       |   236 +
 .../knxnetip/readwrite/model/HostProtocolCode.go   |   122 +
 .../knxnetip/readwrite/model/IPAddress.go          |   152 +
 .../knxnetip/readwrite/model/KnxAddress.go         |   197 +
 .../knxnetip/readwrite/model/KnxDatapoint.go       | 13073 +++++++++++
 .../readwrite/model/KnxDatapointMainType.go        |  1382 ++
 .../knxnetip/readwrite/model/KnxDatapointType.go   |  7142 ++++++
 .../knxnetip/readwrite/model/KnxGroupAddress.go    |   171 +
 .../readwrite/model/KnxGroupAddress2Level.go       |   216 +
 .../readwrite/model/KnxGroupAddress3Level.go       |   242 +
 .../readwrite/model/KnxGroupAddressFreeLevel.go    |   190 +
 .../readwrite/model/KnxInterfaceObjectProperty.go  |  5365 +++++
 .../readwrite/model/KnxInterfaceObjectType.go      |   543 +
 .../protocols/knxnetip/readwrite/model/KnxLayer.go |   130 +
 .../knxnetip/readwrite/model/KnxManufacturer.go    |  9583 ++++++++
 .../knxnetip/readwrite/model/KnxMedium.go          |   154 +
 .../knxnetip/readwrite/model/KnxNetIpCore.go       |   190 +
 .../readwrite/model/KnxNetIpDeviceManagement.go    |   190 +
 .../knxnetip/readwrite/model/KnxNetIpMessage.go    |   283 +
 .../knxnetip/readwrite/model/KnxNetIpRouting.go    |   190 +
 .../knxnetip/readwrite/model/KnxNetIpTunneling.go  |   190 +
 .../knxnetip/readwrite/model/KnxNetObjectServer.go |   190 +
 .../model/KnxNetRemoteConfigurationAndDiagnosis.go |   190 +
 .../readwrite/model/KnxNetRemoteLogging.go         |   190 +
 .../knxnetip/readwrite/model/KnxProperty.go        |  1402 ++
 .../readwrite/model/KnxPropertyDataType.go         |  1162 +
 .../knxnetip/readwrite/model/LBusmonInd.go         |   317 +
 .../protocols/knxnetip/readwrite/model/LDataCon.go |   283 +
 .../knxnetip/readwrite/model/LDataExtended.go      |   372 +
 .../knxnetip/readwrite/model/LDataFrame.go         |   346 +
 .../knxnetip/readwrite/model/LDataFrameACK.go      |   163 +
 .../protocols/knxnetip/readwrite/model/LDataInd.go |   283 +
 .../protocols/knxnetip/readwrite/model/LDataReq.go |   283 +
 .../knxnetip/readwrite/model/LPollData.go          |   292 +
 .../knxnetip/readwrite/model/LPollDataCon.go       |   156 +
 .../knxnetip/readwrite/model/LPollDataReq.go       |   156 +
 .../protocols/knxnetip/readwrite/model/LRawCon.go  |   156 +
 .../protocols/knxnetip/readwrite/model/LRawInd.go  |   156 +
 .../protocols/knxnetip/readwrite/model/LRawReq.go  |   156 +
 .../knxnetip/readwrite/model/MACAddress.go         |   152 +
 .../readwrite/model/MFuncPropCommandReq.go         |   156 +
 .../knxnetip/readwrite/model/MFuncPropCon.go       |   156 +
 .../readwrite/model/MFuncPropStateReadReq.go       |   156 +
 .../knxnetip/readwrite/model/MPropInfoInd.go       |   156 +
 .../knxnetip/readwrite/model/MPropReadCon.go       |   323 +
 .../knxnetip/readwrite/model/MPropReadReq.go       |   297 +
 .../knxnetip/readwrite/model/MPropWriteCon.go      |   156 +
 .../knxnetip/readwrite/model/MPropWriteReq.go      |   156 +
 .../knxnetip/readwrite/model/MResetInd.go          |   156 +
 .../knxnetip/readwrite/model/MResetReq.go          |   156 +
 .../model/ProjectInstallationIdentifier.go         |   173 +
 .../knxnetip/readwrite/model/RelativeTimestamp.go  |   149 +
 .../knxnetip/readwrite/model/RoutingIndication.go  |   153 +
 .../knxnetip/readwrite/model/SearchRequest.go      |   201 +
 .../knxnetip/readwrite/model/SearchResponse.go     |   275 +
 .../knxnetip/readwrite/model/ServiceId.go          |   195 +
 .../protocols/knxnetip/readwrite/model/Status.go   |   202 +
 .../readwrite/model/SupportedPhysicalMedia.go      |   479 +
 .../knxnetip/readwrite/model/TDataConnectedInd.go  |   156 +
 .../knxnetip/readwrite/model/TDataConnectedReq.go  |   156 +
 .../knxnetip/readwrite/model/TDataIndividualInd.go |   156 +
 .../knxnetip/readwrite/model/TDataIndividualReq.go |   156 +
 .../knxnetip/readwrite/model/TunnelingRequest.go   |   241 +
 .../readwrite/model/TunnelingRequestDataBlock.go   |   216 +
 .../knxnetip/readwrite/model/TunnelingResponse.go  |   201 +
 .../readwrite/model/TunnelingResponseDataBlock.go  |   225 +
 .../knxnetip/readwrite/model/UnknownMessage.go     |   196 +
 plc4go/protocols/modbus/readwrite/ParserHelper.go  |    69 +
 .../protocols/modbus/readwrite/XmlParserHelper.go  |    74 +
 .../protocols/modbus/readwrite/model/DataItem.go   |   657 +
 .../protocols/modbus/readwrite/model/DriverType.go |   130 +
 .../protocols/modbus/readwrite/model/ModbusADU.go  |   174 +
 .../modbus/readwrite/model/ModbusAsciiADU.go       |   260 +
 .../modbus/readwrite/model/ModbusConstants.go      |   151 +
 .../modbus/readwrite/model/ModbusDataType.go       |   448 +
 .../ModbusDeviceInformationConformityLevel.go      |   130 +
 .../model/ModbusDeviceInformationLevel.go          |   138 +
 .../model/ModbusDeviceInformationMoreFollows.go    |   122 +
 .../model/ModbusDeviceInformationObject.go         |   193 +
 .../modbus/readwrite/model/ModbusErrorCode.go      |   186 +
 .../protocols/modbus/readwrite/model/ModbusPDU.go  |   279 +
 .../readwrite/model/ModbusPDUDiagnosticRequest.go  |   224 +
 .../readwrite/model/ModbusPDUDiagnosticResponse.go |   224 +
 .../modbus/readwrite/model/ModbusPDUError.go       |   209 +
 .../model/ModbusPDUGetComEventCounterRequest.go    |   161 +
 .../model/ModbusPDUGetComEventCounterResponse.go   |   224 +
 .../model/ModbusPDUGetComEventLogRequest.go        |   161 +
 .../model/ModbusPDUGetComEventLogResponse.go       |   296 +
 .../ModbusPDUMaskWriteHoldingRegisterRequest.go    |   250 +
 .../ModbusPDUMaskWriteHoldingRegisterResponse.go   |   250 +
 .../readwrite/model/ModbusPDUReadCoilsRequest.go   |   224 +
 .../readwrite/model/ModbusPDUReadCoilsResponse.go  |   218 +
 .../ModbusPDUReadDeviceIdentificationRequest.go    |   270 +
 .../ModbusPDUReadDeviceIdentificationResponse.go   |   439 +
 .../model/ModbusPDUReadDiscreteInputsRequest.go    |   224 +
 .../model/ModbusPDUReadDiscreteInputsResponse.go   |   218 +
 .../model/ModbusPDUReadExceptionStatusRequest.go   |   161 +
 .../model/ModbusPDUReadExceptionStatusResponse.go  |   198 +
 .../model/ModbusPDUReadFifoQueueRequest.go         |   198 +
 .../model/ModbusPDUReadFifoQueueResponse.go        |   255 +
 .../model/ModbusPDUReadFileRecordRequest.go        |   249 +
 .../model/ModbusPDUReadFileRecordRequestItem.go    |   221 +
 .../model/ModbusPDUReadFileRecordResponse.go       |   249 +
 .../model/ModbusPDUReadFileRecordResponseItem.go   |   193 +
 .../model/ModbusPDUReadHoldingRegistersRequest.go  |   224 +
 .../model/ModbusPDUReadHoldingRegistersResponse.go |   218 +
 .../model/ModbusPDUReadInputRegistersRequest.go    |   224 +
 .../model/ModbusPDUReadInputRegistersResponse.go   |   218 +
 ...sPDUReadWriteMultipleHoldingRegistersRequest.go |   322 +
 ...PDUReadWriteMultipleHoldingRegistersResponse.go |   218 +
 .../model/ModbusPDUReportServerIdRequest.go        |   161 +
 .../model/ModbusPDUReportServerIdResponse.go       |   218 +
 .../model/ModbusPDUWriteFileRecordRequest.go       |   249 +
 .../model/ModbusPDUWriteFileRecordRequestItem.go   |   241 +
 .../model/ModbusPDUWriteFileRecordResponse.go      |   249 +
 .../model/ModbusPDUWriteFileRecordResponseItem.go  |   241 +
 .../model/ModbusPDUWriteMultipleCoilsRequest.go    |   270 +
 .../model/ModbusPDUWriteMultipleCoilsResponse.go   |   224 +
 ...odbusPDUWriteMultipleHoldingRegistersRequest.go |   270 +
 ...dbusPDUWriteMultipleHoldingRegistersResponse.go |   224 +
 .../model/ModbusPDUWriteSingleCoilRequest.go       |   224 +
 .../model/ModbusPDUWriteSingleCoilResponse.go      |   224 +
 .../model/ModbusPDUWriteSingleRegisterRequest.go   |   224 +
 .../model/ModbusPDUWriteSingleRegisterResponse.go  |   224 +
 .../modbus/readwrite/model/ModbusRtuADU.go         |   260 +
 .../modbus/readwrite/model/ModbusTcpADU.go         |   308 +
 .../modbus/readwrite/model/StaticHelper.go         |     0
 plc4go/protocols/s7/readwrite/ParserHelper.go      |   130 +
 plc4go/protocols/s7/readwrite/XmlParserHelper.go   |   147 +
 .../model/AlarmMessageAckObjectPushType.go         |   337 +
 .../s7/readwrite/model/AlarmMessageAckPushType.go  |   258 +
 .../readwrite/model/AlarmMessageAckResponseType.go |   220 +
 .../s7/readwrite/model/AlarmMessageAckType.go      |   223 +
 .../readwrite/model/AlarmMessageObjectAckType.go   |   336 +
 .../readwrite/model/AlarmMessageObjectPushType.go  |   457 +
 .../readwrite/model/AlarmMessageObjectQueryType.go |   455 +
 .../s7/readwrite/model/AlarmMessagePushType.go     |   258 +
 .../s7/readwrite/model/AlarmMessageQueryType.go    |   328 +
 .../protocols/s7/readwrite/model/AlarmStateType.go |   154 +
 plc4go/protocols/s7/readwrite/model/AlarmType.go   |   130 +
 .../s7/readwrite/model/AssociatedValueType.go      |   265 +
 plc4go/protocols/s7/readwrite/model/COTPPacket.go  |   329 +
 .../readwrite/model/COTPPacketConnectionRequest.go |   259 +
 .../model/COTPPacketConnectionResponse.go          |   259 +
 .../protocols/s7/readwrite/model/COTPPacketData.go |   222 +
 .../readwrite/model/COTPPacketDisconnectRequest.go |   259 +
 .../model/COTPPacketDisconnectResponse.go          |   222 +
 .../s7/readwrite/model/COTPPacketTpduError.go      |   222 +
 .../protocols/s7/readwrite/model/COTPParameter.go  |   211 +
 .../s7/readwrite/model/COTPParameterCalledTsap.go  |   193 +
 .../s7/readwrite/model/COTPParameterCallingTsap.go |   193 +
 .../s7/readwrite/model/COTPParameterChecksum.go    |   193 +
 ...COTPParameterDisconnectAdditionalInformation.go |   196 +
 .../s7/readwrite/model/COTPParameterTpduSize.go    |   204 +
 .../s7/readwrite/model/COTPProtocolClass.go        |   146 +
 .../protocols/s7/readwrite/model/COTPTpduSize.go   |   208 +
 .../s7/readwrite/model/CpuSubscribeEvents.go       |   138 +
 plc4go/protocols/s7/readwrite/model/DataItem.go    |   489 +
 .../s7/readwrite/model/DataTransportErrorCode.go   |   154 +
 .../s7/readwrite/model/DataTransportSize.go        |   208 +
 plc4go/protocols/s7/readwrite/model/DateAndTime.go |   310 +
 plc4go/protocols/s7/readwrite/model/DeviceGroup.go |   130 +
 plc4go/protocols/s7/readwrite/model/EventType.go   |   138 +
 plc4go/protocols/s7/readwrite/model/MemoryArea.go  |   232 +
 .../s7/readwrite/model/ModeTransitionType.go       |   178 +
 plc4go/protocols/s7/readwrite/model/QueryType.go   |   130 +
 plc4go/protocols/s7/readwrite/model/S7Address.go   |   183 +
 .../protocols/s7/readwrite/model/S7AddressAny.go   |   371 +
 .../s7/readwrite/model/S7DataAlarmMessage.go       |   228 +
 plc4go/protocols/s7/readwrite/model/S7Message.go   |   417 +
 .../s7/readwrite/model/S7MessageObjectRequest.go   |   384 +
 .../s7/readwrite/model/S7MessageObjectResponse.go  |   264 +
 .../s7/readwrite/model/S7MessageRequest.go         |   157 +
 .../s7/readwrite/model/S7MessageResponse.go        |   220 +
 .../s7/readwrite/model/S7MessageResponseData.go    |   220 +
 .../s7/readwrite/model/S7MessageUserData.go        |   157 +
 plc4go/protocols/s7/readwrite/model/S7Parameter.go |   197 +
 .../readwrite/model/S7ParameterModeTransition.go   |   341 +
 .../readwrite/model/S7ParameterReadVarRequest.go   |   237 +
 .../readwrite/model/S7ParameterReadVarResponse.go  |   194 +
 .../model/S7ParameterSetupCommunication.go         |   272 +
 .../s7/readwrite/model/S7ParameterUserData.go      |   237 +
 .../s7/readwrite/model/S7ParameterUserDataItem.go  |   183 +
 .../model/S7ParameterUserDataItemCPUFunctions.go   |   413 +
 .../readwrite/model/S7ParameterWriteVarRequest.go  |   237 +
 .../readwrite/model/S7ParameterWriteVarResponse.go |   194 +
 plc4go/protocols/s7/readwrite/model/S7Payload.go   |   178 +
 .../s7/readwrite/model/S7PayloadAlarm8.go          |   212 +
 .../s7/readwrite/model/S7PayloadAlarmAckInd.go     |   212 +
 .../s7/readwrite/model/S7PayloadAlarmS.go          |   212 +
 .../s7/readwrite/model/S7PayloadAlarmSC.go         |   212 +
 .../s7/readwrite/model/S7PayloadAlarmSQ.go         |   212 +
 .../readwrite/model/S7PayloadDiagnosticMessage.go  |   368 +
 .../s7/readwrite/model/S7PayloadNotify.go          |   212 +
 .../s7/readwrite/model/S7PayloadNotify8.go         |   212 +
 .../s7/readwrite/model/S7PayloadReadVarResponse.go |   223 +
 .../s7/readwrite/model/S7PayloadUserData.go        |   223 +
 .../s7/readwrite/model/S7PayloadUserDataItem.go    |   302 +
 .../S7PayloadUserDataItemCpuFunctionAlarmAck.go    |   270 +
 ...yloadUserDataItemCpuFunctionAlarmAckResponse.go |   267 +
 .../S7PayloadUserDataItemCpuFunctionAlarmQuery.go  |   441 +
 ...oadUserDataItemCpuFunctionAlarmQueryResponse.go |   333 +
 ...ayloadUserDataItemCpuFunctionMsgSubscription.go |   333 +
 ...aItemCpuFunctionMsgSubscriptionAlarmResponse.go |   316 +
 ...erDataItemCpuFunctionMsgSubscriptionResponse.go |   164 +
 ...ataItemCpuFunctionMsgSubscriptionSysResponse.go |   227 +
 ...PayloadUserDataItemCpuFunctionReadSzlRequest.go |   238 +
 ...ayloadUserDataItemCpuFunctionReadSzlResponse.go |   342 +
 .../s7/readwrite/model/S7PayloadWriteVarRequest.go |   223 +
 .../readwrite/model/S7PayloadWriteVarResponse.go   |   223 +
 .../s7/readwrite/model/S7VarPayloadDataItem.go     |   284 +
 .../s7/readwrite/model/S7VarPayloadStatusItem.go   |   160 +
 .../readwrite/model/S7VarRequestParameterItem.go   |   183 +
 .../model/S7VarRequestParameterItemAddress.go      |   218 +
 plc4go/protocols/s7/readwrite/model/State.go       |   317 +
 .../protocols/s7/readwrite/model/StaticHelper.go   |   181 +
 .../protocols/s7/readwrite/model/SyntaxIdType.go   |   210 +
 .../s7/readwrite/model/SzlDataTreeItem.go          |   248 +
 plc4go/protocols/s7/readwrite/model/SzlId.go       |   219 +
 .../s7/readwrite/model/SzlModuleTypeClass.go       |   138 +
 plc4go/protocols/s7/readwrite/model/SzlSublist.go  |   258 +
 plc4go/protocols/s7/readwrite/model/TPKTPacket.go  |   238 +
 .../protocols/s7/readwrite/model/TransportSize.go  |  1666 ++
 .../protocols/simulated/readwrite/ParserHelper.go  |    49 +
 .../simulated/readwrite/XmlParserHelper.go         |    58 +
 .../simulated/readwrite/model/DataItem.go          |   643 +
 .../protocols/simulated/readwrite/model/Dummy.go   |   149 +
 .../readwrite/model/SimulatedDataTypeSizes.go      |   448 +
 2364 files changed, 348025 insertions(+), 348577 deletions(-)

diff --git a/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java b/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java
index 1609219dbc..16e5d1b533 100644
--- a/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java
+++ b/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java
@@ -53,7 +53,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
     }
 
     public String fileName(String protocolName, String languageName, String languageFlavorName) {
-        return "plc4go." + String.join("", protocolName.split("\\-")) + "." +
+        return String.join("", protocolName.split("\\-")) + "." +
             String.join("", languageFlavorName.split("\\-"));
     }
 
diff --git a/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/utils/FieldUtils.java b/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/utils/FieldUtils.java
deleted file mode 100644
index 70402263f2..0000000000
--- a/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/utils/FieldUtils.java
+++ /dev/null
@@ -1,103 +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.go.utils;
-
-import org.apache.plc4x.plugins.codegenerator.types.fields.*;
-import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
-
-public class FieldUtils {
-
-    public static boolean contains(Field field, String label) {
-        switch(field.getTypeName()) {
-            case "array": {
-                ArrayField arrayField = (ArrayField) field;
-                return arrayField.getLoopExpression().contains(label);
-            }
-            case "checksum": {
-                ChecksumField checksumField = (ChecksumField) field;
-                return checksumField.getChecksumExpression().contains(label);
-            }
-            case "const": {
-                ConstField constField = (ConstField) field;
-                return false;
-            }
-            case "discriminator": {
-                DiscriminatorField discriminatorField = (DiscriminatorField) field;
-                return false;
-            }
-            case "enum": {
-                EnumField enumField = (EnumField) field;
-                return false;
-            }
-            case "implicit": {
-                ImplicitField implicitField = (ImplicitField) field;
-                return implicitField.getSerializeExpression().contains(label);
-            }
-            case "manualArray": {
-                ManualArrayField manualArrayField = (ManualArrayField) field;
-                return
-                    manualArrayField.getSerializeExpression().contains(label) ||
-                        manualArrayField.getParseExpression().contains(label) ||
-                        manualArrayField.getLoopExpression().contains(label) ||
-                        manualArrayField.getLengthExpression().contains(label);
-            }
-            case "manual": {
-                ManualField manualField = (ManualField) field;
-                return
-                    manualField.getSerializeExpression().contains(label) ||
-                        manualField.getParseExpression().contains(label) ||
-                        manualField.getLengthExpression().contains(label);
-            }
-            case "optional": {
-                OptionalField optionalField = (OptionalField) field;
-                return optionalField.getConditionExpression().isPresent() && optionalField.getConditionExpression().orElseThrow(IllegalStateException::new).contains(label);
-            }
-            case "padding": {
-                PaddingField paddingField = (PaddingField) field;
-                return
-                    paddingField.getPaddingCondition().contains(label) ||
-                        paddingField.getPaddingValue().contains(label);
-            }
-            case "reserved": {
-                ReservedField reservedField = (ReservedField) field;
-                return false;
-            }
-            case "simple": {
-                SimpleField simpleField = (SimpleField) field;
-                return false;
-            }
-            case "switch": {
-                SwitchField switchField = (SwitchField) field;
-                for (Term discriminatorExpression : switchField.getDiscriminatorExpressions()) {
-                    if(discriminatorExpression.contains(label)) {
-                        return true;
-                    }
-                }
-                return false;
-            }
-            case "virtual": {
-                VirtualField virtualField = (VirtualField) field;
-                return virtualField.getValueExpression().contains(label);
-            }
-        }
-        return false;
-    }
-
-
-}
diff --git a/code-generation/language-go/src/main/resources/templates/go/complex-type-template.go.ftlh b/code-generation/language-go/src/main/resources/templates/go/complex-type-template.go.ftlh
index e6bd4982e0..796205db3a 100644
--- a/code-generation/language-go/src/main/resources/templates/go/complex-type-template.go.ftlh
+++ b/code-generation/language-go/src/main/resources/templates/go/complex-type-template.go.ftlh
@@ -63,7 +63,7 @@ import (
 <#macro emitImport import>${helper.emitRequiredImport(import)}</#macro>
 <#macro emitImportWithAlias alias import>${helper.emitRequiredImport(alias, import)}</#macro>
 
-<@importSectionWithContentBelow><@emitImport import="github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils" />
+<@importSectionWithContentBelow><@emitImport import="github.com/apache/plc4x/plc4go/internal/spi/utils" />
 // Code generated by code-generation. DO NOT EDIT.
 
 <#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
diff --git a/code-generation/language-go/src/main/resources/templates/go/data-io-template.go.ftlh b/code-generation/language-go/src/main/resources/templates/go/data-io-template.go.ftlh
index e30cdecdbb..ea72454c87 100644
--- a/code-generation/language-go/src/main/resources/templates/go/data-io-template.go.ftlh
+++ b/code-generation/language-go/src/main/resources/templates/go/data-io-template.go.ftlh
@@ -63,7 +63,7 @@ import (
 <#macro emitImport import>${helper.emitDataIoRequiredImport(import)}</#macro>
 <#macro emitImportWithAlias alias import>${helper.emitDataIoRequiredImport(alias, import)}</#macro>
 
-<@importSectionWithContentBelow><@emitImport import="github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils" /><@emitImport import="github.com/apache/plc4x/plc4go/internal/plc4go/spi/values" /><@emitImportWithAlias alias="api" import="github.com/apache/plc4x/plc4go/pkg/plc4go/values" />
+<@importSectionWithContentBelow><@emitImport import="github.com/apache/plc4x/plc4go/internal/spi/utils" /><@emitImport import="github.com/apache/plc4x/plc4go/internal/spi/values" /><@emitImportWithAlias alias="api" import="github.com/apache/plc4x/plc4go/pkg/plc4go/values" />
 // Code generated by code-generation. DO NOT EDIT.
 	
 <#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
diff --git a/code-generation/language-go/src/main/resources/templates/go/enum-template.go.ftlh b/code-generation/language-go/src/main/resources/templates/go/enum-template.go.ftlh
index 9593df8952..9c283494db 100644
--- a/code-generation/language-go/src/main/resources/templates/go/enum-template.go.ftlh
+++ b/code-generation/language-go/src/main/resources/templates/go/enum-template.go.ftlh
@@ -49,7 +49,7 @@ ${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/m
 package model
 
 import (
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
 	"github.com/pkg/errors"
 )
 
diff --git a/code-generation/language-go/src/main/resources/templates/go/parser-factory-template.go.ftlh b/code-generation/language-go/src/main/resources/templates/go/parser-factory-template.go.ftlh
index b278fffeb7..9b27979aad 100644
--- a/code-generation/language-go/src/main/resources/templates/go/parser-factory-template.go.ftlh
+++ b/code-generation/language-go/src/main/resources/templates/go/parser-factory-template.go.ftlh
@@ -48,8 +48,8 @@ ${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/P
 package ${outputFlavor?replace("-","")}
 
 import (
-	"github.com/apache/plc4x/plc4go/internal/plc4go/${helper.getSanitizedProtocolName()}/${outputFlavor?replace("-","")}/model"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils"
+	"github.com/apache/plc4x/plc4go/protocols/${helper.getSanitizedProtocolName()}/${outputFlavor?replace("-","")}/model"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
 	"github.com/pkg/errors"
 )
 
diff --git a/code-generation/language-go/src/main/resources/templates/go/xml-parser-factory-template.go.ftlh b/code-generation/language-go/src/main/resources/templates/go/xml-parser-factory-template.go.ftlh
index 0fdcea0dc8..b95f3f0a04 100644
--- a/code-generation/language-go/src/main/resources/templates/go/xml-parser-factory-template.go.ftlh
+++ b/code-generation/language-go/src/main/resources/templates/go/xml-parser-factory-template.go.ftlh
@@ -48,8 +48,8 @@ ${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/X
 package ${outputFlavor?replace("-","")}
 
 import (
-	"github.com/apache/plc4x/plc4go/internal/plc4go/${helper.getSanitizedProtocolName()}/${outputFlavor?replace("-","")}/model"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils"
+	"github.com/apache/plc4x/plc4go/protocols/${helper.getSanitizedProtocolName()}/${outputFlavor?replace("-","")}/model"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
 	"github.com/pkg/errors"
     "strings"
     "strconv"
diff --git a/code-generation/language-go/src/test/resources/plc4go/internal/plc4go/test/readwrite/model/StaticHelper.go b/code-generation/language-go/src/test/resources/plc4go/internal/plc4go/test/readwrite/model/StaticHelper.go
index def83ca964..8394babf04 100644
--- a/code-generation/language-go/src/test/resources/plc4go/internal/plc4go/test/readwrite/model/StaticHelper.go
+++ b/code-generation/language-go/src/test/resources/plc4go/internal/plc4go/test/readwrite/model/StaticHelper.go
@@ -19,7 +19,7 @@
 
 package model
 
-import "github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils"
+import "github.com/apache/plc4x/plc4go/internal/spi/utils"
 
 func ParseBit(io utils.ReadBuffer) int8 {
 	return 0
diff --git a/code-generation/language-go/src/test/resources/plc4go/pom.xml b/code-generation/language-go/src/test/resources/plc4go/pom.xml
index 3106619c2d..0a14e1a44a 100644
--- a/code-generation/language-go/src/test/resources/plc4go/pom.xml
+++ b/code-generation/language-go/src/test/resources/plc4go/pom.xml
@@ -71,7 +71,7 @@
             <resources>
               <resource>
                 <targetPath>.</targetPath>
-                <directory>../../../../../plc4go/internal/plc4go/spi</directory>
+                <directory>../../../../../internal/spi</directory>
                 <excludes>
                   <exclude>testutils/**</exclude>
                 </excludes>
diff --git a/plc4go/cmd/main/drivers/s7_test.go b/plc4go/cmd/main/drivers/s7_test.go
index 3a47ff4c3f..3aa0109aef 100644
--- a/plc4go/cmd/main/drivers/s7_test.go
+++ b/plc4go/cmd/main/drivers/s7_test.go
@@ -22,8 +22,8 @@ package drivers
 import (
 	"encoding/hex"
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/s7/readwrite/model"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/apache/plc4x/plc4go/protocols/s7/readwrite/model"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/abeth_driver_test.go b/plc4go/cmd/main/drivers/tests/abeth_driver_test.go
index a9458d73a3..bf84ae0133 100644
--- a/plc4go/cmd/main/drivers/tests/abeth_driver_test.go
+++ b/plc4go/cmd/main/drivers/tests/abeth_driver_test.go
@@ -21,9 +21,9 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	abethIO "github.com/apache/plc4x/plc4go/internal/plc4go/abeth/readwrite"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/ads"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/ads"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
+	abethIO "github.com/apache/plc4x/plc4go/protocols/abeth/readwrite"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/abeth_parser_serializer_test.go b/plc4go/cmd/main/drivers/tests/abeth_parser_serializer_test.go
index b1505ce0cf..86788fac48 100644
--- a/plc4go/cmd/main/drivers/tests/abeth_parser_serializer_test.go
+++ b/plc4go/cmd/main/drivers/tests/abeth_parser_serializer_test.go
@@ -21,7 +21,7 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/ads_driver_test.go b/plc4go/cmd/main/drivers/tests/ads_driver_test.go
index a11301fdf0..538df3bbea 100644
--- a/plc4go/cmd/main/drivers/tests/ads_driver_test.go
+++ b/plc4go/cmd/main/drivers/tests/ads_driver_test.go
@@ -21,11 +21,11 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/ads"
-	adsIO "github.com/apache/plc4x/plc4go/internal/plc4go/ads/readwrite"
-	adsModel "github.com/apache/plc4x/plc4go/internal/plc4go/ads/readwrite/model"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils"
+	"github.com/apache/plc4x/plc4go/internal/ads"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	adsIO "github.com/apache/plc4x/plc4go/protocols/ads/readwrite"
+	adsModel "github.com/apache/plc4x/plc4go/protocols/ads/readwrite/model"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/ads_parser_serializer_test.go b/plc4go/cmd/main/drivers/tests/ads_parser_serializer_test.go
index 96cf0e22ea..6a30eb1764 100644
--- a/plc4go/cmd/main/drivers/tests/ads_parser_serializer_test.go
+++ b/plc4go/cmd/main/drivers/tests/ads_parser_serializer_test.go
@@ -21,7 +21,7 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/bacnet_parser_serializer_test.go b/plc4go/cmd/main/drivers/tests/bacnet_parser_serializer_test.go
index e056fd0640..6333bbb947 100644
--- a/plc4go/cmd/main/drivers/tests/bacnet_parser_serializer_test.go
+++ b/plc4go/cmd/main/drivers/tests/bacnet_parser_serializer_test.go
@@ -21,7 +21,7 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/df1_driver_test.go b/plc4go/cmd/main/drivers/tests/df1_driver_test.go
index e2eeeedfdd..f8a6dfe846 100644
--- a/plc4go/cmd/main/drivers/tests/df1_driver_test.go
+++ b/plc4go/cmd/main/drivers/tests/df1_driver_test.go
@@ -21,9 +21,9 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/ads"
-	df1IO "github.com/apache/plc4x/plc4go/internal/plc4go/df1/readwrite"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/ads"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
+	df1IO "github.com/apache/plc4x/plc4go/protocols/df1/readwrite"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/df1_parser_serializer_test.go b/plc4go/cmd/main/drivers/tests/df1_parser_serializer_test.go
index c332531141..b3a6aaa869 100644
--- a/plc4go/cmd/main/drivers/tests/df1_parser_serializer_test.go
+++ b/plc4go/cmd/main/drivers/tests/df1_parser_serializer_test.go
@@ -21,7 +21,7 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/eip_driver_test.go b/plc4go/cmd/main/drivers/tests/eip_driver_test.go
index c30835cba4..298cf0f83e 100644
--- a/plc4go/cmd/main/drivers/tests/eip_driver_test.go
+++ b/plc4go/cmd/main/drivers/tests/eip_driver_test.go
@@ -21,11 +21,11 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/eip"
-	eipIO "github.com/apache/plc4x/plc4go/internal/plc4go/eip/readwrite"
-	eipModel "github.com/apache/plc4x/plc4go/internal/plc4go/eip/readwrite/model"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils"
+	"github.com/apache/plc4x/plc4go/internal/eip"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	eipIO "github.com/apache/plc4x/plc4go/protocols/eip/readwrite"
+	eipModel "github.com/apache/plc4x/plc4go/protocols/eip/readwrite/model"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/eip_parser_serializer_test.go b/plc4go/cmd/main/drivers/tests/eip_parser_serializer_test.go
index 164f0ba41c..34ca30ee40 100644
--- a/plc4go/cmd/main/drivers/tests/eip_parser_serializer_test.go
+++ b/plc4go/cmd/main/drivers/tests/eip_parser_serializer_test.go
@@ -21,7 +21,7 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/firmata_driver_test.go b/plc4go/cmd/main/drivers/tests/firmata_driver_test.go
index 6f7187ec3b..9943ec5c19 100644
--- a/plc4go/cmd/main/drivers/tests/firmata_driver_test.go
+++ b/plc4go/cmd/main/drivers/tests/firmata_driver_test.go
@@ -21,9 +21,9 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	firmataIO "github.com/apache/plc4x/plc4go/internal/plc4go/firmata/readwrite"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/knxnetip"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/knxnetip"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
+	firmataIO "github.com/apache/plc4x/plc4go/protocols/firmata/readwrite"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/firmata_parser_serializer_test.go b/plc4go/cmd/main/drivers/tests/firmata_parser_serializer_test.go
index 2a5d69dc59..652977a0e3 100644
--- a/plc4go/cmd/main/drivers/tests/firmata_parser_serializer_test.go
+++ b/plc4go/cmd/main/drivers/tests/firmata_parser_serializer_test.go
@@ -21,7 +21,7 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/knxnetip_driver_test.go b/plc4go/cmd/main/drivers/tests/knxnetip_driver_test.go
index 3e85af8df6..bb894ce7ee 100644
--- a/plc4go/cmd/main/drivers/tests/knxnetip_driver_test.go
+++ b/plc4go/cmd/main/drivers/tests/knxnetip_driver_test.go
@@ -21,11 +21,11 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/knxnetip"
-	knxIO "github.com/apache/plc4x/plc4go/internal/plc4go/knxnetip/readwrite"
-	knxModel "github.com/apache/plc4x/plc4go/internal/plc4go/knxnetip/readwrite/model"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils"
+	"github.com/apache/plc4x/plc4go/internal/knxnetip"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	knxIO "github.com/apache/plc4x/plc4go/protocols/knxnetip/readwrite"
+	knxModel "github.com/apache/plc4x/plc4go/protocols/knxnetip/readwrite/model"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/knxnetip_parser_serializer_test.go b/plc4go/cmd/main/drivers/tests/knxnetip_parser_serializer_test.go
index 7e9442bf4e..513a0e411b 100644
--- a/plc4go/cmd/main/drivers/tests/knxnetip_parser_serializer_test.go
+++ b/plc4go/cmd/main/drivers/tests/knxnetip_parser_serializer_test.go
@@ -21,7 +21,7 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/manual_ads_driver_test.go b/plc4go/cmd/main/drivers/tests/manual_ads_driver_test.go
index 64ad3ae05d..a5fe550498 100644
--- a/plc4go/cmd/main/drivers/tests/manual_ads_driver_test.go
+++ b/plc4go/cmd/main/drivers/tests/manual_ads_driver_test.go
@@ -22,8 +22,8 @@ package tests
 import (
 	"fmt"
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/ads"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/ads"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
 	"github.com/apache/plc4x/plc4go/pkg/plc4go"
 	"github.com/apache/plc4x/plc4go/pkg/plc4go/transports"
 	"testing"
diff --git a/plc4go/cmd/main/drivers/tests/manual_bacnet_PcapTest_test.go b/plc4go/cmd/main/drivers/tests/manual_bacnet_PcapTest_test.go
index e6725e94d4..e8e0f37559 100644
--- a/plc4go/cmd/main/drivers/tests/manual_bacnet_PcapTest_test.go
+++ b/plc4go/cmd/main/drivers/tests/manual_bacnet_PcapTest_test.go
@@ -20,9 +20,9 @@
 package tests
 
 import (
-	"github.com/apache/plc4x/plc4go/internal/plc4go/bacnetip"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/transports/pcap"
+	"github.com/apache/plc4x/plc4go/internal/bacnetip"
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	"github.com/apache/plc4x/plc4go/internal/spi/transports/pcap"
 	"github.com/apache/plc4x/plc4go/pkg/plc4go"
 	"github.com/apache/plc4x/plc4go/pkg/plc4go/config"
 	"github.com/apache/plc4x/plc4go/pkg/plc4go/logging"
diff --git a/plc4go/cmd/main/drivers/tests/manual_s7_driver_test.go b/plc4go/cmd/main/drivers/tests/manual_s7_driver_test.go
index 22b48f65cc..83e1921483 100644
--- a/plc4go/cmd/main/drivers/tests/manual_s7_driver_test.go
+++ b/plc4go/cmd/main/drivers/tests/manual_s7_driver_test.go
@@ -21,8 +21,8 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/s7"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/s7"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
 	"github.com/apache/plc4x/plc4go/pkg/plc4go"
 	"github.com/apache/plc4x/plc4go/pkg/plc4go/transports"
 	"testing"
diff --git a/plc4go/cmd/main/drivers/tests/modbus_driver_test.go b/plc4go/cmd/main/drivers/tests/modbus_driver_test.go
index fea69537cc..60e33bacac 100644
--- a/plc4go/cmd/main/drivers/tests/modbus_driver_test.go
+++ b/plc4go/cmd/main/drivers/tests/modbus_driver_test.go
@@ -21,11 +21,11 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/modbus"
-	modbusIO "github.com/apache/plc4x/plc4go/internal/plc4go/modbus/readwrite"
-	modbusModel "github.com/apache/plc4x/plc4go/internal/plc4go/modbus/readwrite/model"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils"
+	"github.com/apache/plc4x/plc4go/internal/modbus"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	modbusIO "github.com/apache/plc4x/plc4go/protocols/modbus/readwrite"
+	modbusModel "github.com/apache/plc4x/plc4go/protocols/modbus/readwrite/model"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/modbus_parser_serializer_test.go b/plc4go/cmd/main/drivers/tests/modbus_parser_serializer_test.go
index 1284686ce9..01eaa9b595 100644
--- a/plc4go/cmd/main/drivers/tests/modbus_parser_serializer_test.go
+++ b/plc4go/cmd/main/drivers/tests/modbus_parser_serializer_test.go
@@ -21,7 +21,7 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/s7_driver_test.go b/plc4go/cmd/main/drivers/tests/s7_driver_test.go
index 6d0806fba0..3ab19b1eb3 100644
--- a/plc4go/cmd/main/drivers/tests/s7_driver_test.go
+++ b/plc4go/cmd/main/drivers/tests/s7_driver_test.go
@@ -21,11 +21,11 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/s7"
-	s7IO "github.com/apache/plc4x/plc4go/internal/plc4go/s7/readwrite"
-	s7Model "github.com/apache/plc4x/plc4go/internal/plc4go/s7/readwrite/model"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils"
+	"github.com/apache/plc4x/plc4go/internal/s7"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	s7IO "github.com/apache/plc4x/plc4go/protocols/s7/readwrite"
+	s7Model "github.com/apache/plc4x/plc4go/protocols/s7/readwrite/model"
 	"testing"
 )
 
diff --git a/plc4go/cmd/main/drivers/tests/s7_parser_serializer_test.go b/plc4go/cmd/main/drivers/tests/s7_parser_serializer_test.go
index 5124b67349..31989ad1a6 100644
--- a/plc4go/cmd/main/drivers/tests/s7_parser_serializer_test.go
+++ b/plc4go/cmd/main/drivers/tests/s7_parser_serializer_test.go
@@ -21,7 +21,7 @@ package tests
 
 import (
 	_ "github.com/apache/plc4x/plc4go/cmd/main/initializetest"
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/testutils"
+	"github.com/apache/plc4x/plc4go/internal/spi/testutils"
 	"testing"
 )
 
diff --git a/plc4go/examples/knx/discovery/hello_world_plc4go_knx_discovery.go b/plc4go/examples/knx/discovery/hello_world_plc4go_knx_discovery.go
index ed632f9f8c..e339667f77 100644
--- a/plc4go/examples/knx/discovery/hello_world_plc4go_knx_discovery.go
+++ b/plc4go/examples/knx/discovery/hello_world_plc4go_knx_discovery.go
@@ -20,7 +20,7 @@
 package main
 
 import (
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
 	"github.com/apache/plc4x/plc4go/pkg/plc4go"
 	"github.com/apache/plc4x/plc4go/pkg/plc4go/drivers"
 	"github.com/apache/plc4x/plc4go/pkg/plc4go/logging"
diff --git a/plc4go/internal/ads/Configuration.go b/plc4go/internal/ads/Configuration.go
new file mode 100644
index 0000000000..f401101dee
--- /dev/null
+++ b/plc4go/internal/ads/Configuration.go
@@ -0,0 +1,147 @@
+/*
+ * 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 ads
+
+import (
+	readWriteModel "github.com/apache/plc4x/plc4go/protocols/ads/readwrite/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+	"strconv"
+	"strings"
+)
+
+type Configuration struct {
+	sourceAmsNetId readWriteModel.AmsNetId
+	sourceAmsPort  uint16
+	targetAmsNetId readWriteModel.AmsNetId
+	targetAmsPort  uint16
+}
+
+func ParseFromOptions(options map[string][]string) (Configuration, error) {
+	configuration := Configuration{}
+
+	sourceAmsNetId := getFromOptions(options, "sourceAmsNetId")
+	if sourceAmsNetId == "" {
+		return Configuration{}, errors.New("Required parameter sourceAmsNetId missing")
+	}
+	split := strings.Split(sourceAmsNetId, ".")
+	octet1, err := strconv.ParseUint(split[0], 10, 8)
+	if err != nil {
+		return Configuration{}, errors.Wrap(err, "error parsing sourceAmsNetId")
+	}
+	octet2, err := strconv.ParseUint(split[1], 10, 8)
+	if err != nil {
+		return Configuration{}, errors.Wrap(err, "error parsing sourceAmsNetId")
+	}
+	octet3, err := strconv.ParseUint(split[2], 10, 8)
+	if err != nil {
+		return Configuration{}, errors.Wrap(err, "error parsing sourceAmsNetId")
+	}
+	octet4, err := strconv.ParseUint(split[3], 10, 8)
+	if err != nil {
+		return Configuration{}, errors.Wrap(err, "error parsing sourceAmsNetId")
+	}
+	octet5, err := strconv.ParseUint(split[4], 10, 8)
+	if err != nil {
+		return Configuration{}, errors.Wrap(err, "error parsing sourceAmsNetId")
+	}
+	octet6, err := strconv.ParseUint(split[5], 10, 8)
+	if err != nil {
+		return Configuration{}, errors.Wrap(err, "error parsing sourceAmsNetId")
+	}
+	configuration.sourceAmsNetId = readWriteModel.AmsNetId{
+		Octet1: uint8(octet1),
+		Octet2: uint8(octet2),
+		Octet3: uint8(octet3),
+		Octet4: uint8(octet4),
+		Octet5: uint8(octet5),
+		Octet6: uint8(octet6),
+	}
+	sourceAmsPort := getFromOptions(options, "sourceAmsPort")
+	if sourceAmsPort == "" {
+		return Configuration{}, errors.New("Required parameter sourceAmsPort missing")
+	}
+	parsedUint, err := strconv.ParseUint(sourceAmsPort, 10, 16)
+	if err != nil {
+		return Configuration{}, errors.Wrap(err, "error parsing sourceAmsPort")
+	}
+	configuration.sourceAmsPort = uint16(parsedUint)
+	targetAmsNetId := getFromOptions(options, "targetAmsNetId")
+	if sourceAmsNetId == "" {
+		return Configuration{}, errors.New("Required parameter targetAmsNetId missing")
+	}
+	split = strings.Split(targetAmsNetId, ".")
+	octet1, err = strconv.ParseUint(split[0], 10, 8)
+	if err != nil {
+		return Configuration{}, errors.Wrap(err, "error parsing targetAmsNetId")
+	}
+	octet2, err = strconv.ParseUint(split[1], 10, 8)
+	if err != nil {
+		return Configuration{}, errors.Wrap(err, "error parsing targetAmsNetId")
+	}
+	octet3, err = strconv.ParseUint(split[2], 10, 8)
+	if err != nil {
+		return Configuration{}, errors.Wrap(err, "error parsing targetAmsNetId")
+	}
+	octet4, err = strconv.ParseUint(split[3], 10, 8)
+	if err != nil {
+		return Configuration{}, errors.Wrap(err, "error parsing targetAmsNetId")
+	}
+	octet5, err = strconv.ParseUint(split[4], 10, 8)
+	if err != nil {
+		return Configuration{}, errors.Wrap(err, "error parsing targetAmsNetId")
+	}
+	octet6, err = strconv.ParseUint(split[5], 10, 8)
+	if err != nil {
+		return Configuration{}, errors.Wrap(err, "error parsing targetAmsNetId")
+	}
+	configuration.targetAmsNetId = readWriteModel.AmsNetId{
+		Octet1: uint8(octet1),
+		Octet2: uint8(octet2),
+		Octet3: uint8(octet3),
+		Octet4: uint8(octet4),
+		Octet5: uint8(octet5),
+		Octet6: uint8(octet6),
+	}
+	targetAmsPort := getFromOptions(options, "targetAmsPort")
+	if targetAmsPort == "" {
+		return Configuration{}, errors.New("Required parameter targetAmsPort missing")
+	}
+	parsedUint, err = strconv.ParseUint(targetAmsPort, 10, 16)
+	if err != nil {
+		return Configuration{}, errors.Wrap(err, "error parsing targetAmsPort")
+	}
+	configuration.targetAmsPort = uint16(parsedUint)
+
+	return configuration, nil
+}
+
+func getFromOptions(options map[string][]string, key string) string {
+	if optionValues, ok := options[key]; ok {
+		if len(optionValues) <= 0 {
+			return ""
+		}
+		if len(optionValues) > 1 {
+			log.Warn().Msgf("Options %s must be unique", key)
+		}
+		return optionValues[0]
+	}
+	return ""
+}
diff --git a/plc4go/internal/ads/Connection.go b/plc4go/internal/ads/Connection.go
new file mode 100644
index 0000000000..65efa30071
--- /dev/null
+++ b/plc4go/internal/ads/Connection.go
@@ -0,0 +1,136 @@
+/*
+ * 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 ads
+
+import (
+	"fmt"
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	"github.com/apache/plc4x/plc4go/internal/spi/default"
+	"github.com/apache/plc4x/plc4go/internal/spi/interceptors"
+	internalModel "github.com/apache/plc4x/plc4go/internal/spi/model"
+	"github.com/apache/plc4x/plc4go/internal/spi/transports"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go"
+	apiModel "github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+)
+
+type Connection struct {
+	_default.DefaultConnection
+	messageCodec       spi.MessageCodec
+	requestInterceptor interceptors.RequestInterceptor
+	configuration      Configuration
+	reader             *Reader
+	writer             *Writer
+	connectionId       string
+	tracer             *spi.Tracer
+}
+
+func NewConnection(messageCodec spi.MessageCodec, configuration Configuration, fieldHandler spi.PlcFieldHandler, options map[string][]string) (*Connection, error) {
+	reader := *NewReader(
+		messageCodec,
+		configuration.targetAmsNetId,
+		configuration.targetAmsPort,
+		configuration.sourceAmsNetId,
+		configuration.sourceAmsPort,
+	)
+	writer := *NewWriter(
+		messageCodec,
+		configuration.targetAmsNetId,
+		configuration.targetAmsPort,
+		configuration.sourceAmsNetId,
+		configuration.sourceAmsPort,
+		&reader,
+	)
+	connection := &Connection{
+		messageCodec: messageCodec,
+		requestInterceptor: interceptors.NewSingleItemRequestInterceptor(
+			internalModel.NewDefaultPlcReadRequest,
+			internalModel.NewDefaultPlcWriteRequest,
+			internalModel.NewDefaultPlcReadResponse,
+			internalModel.NewDefaultPlcWriteResponse,
+		),
+		reader: &reader,
+		writer: &writer,
+	}
+	if traceEnabledOption, ok := options["traceEnabled"]; ok {
+		if len(traceEnabledOption) == 1 {
+			connection.tracer = spi.NewTracer(connection.connectionId)
+		}
+	}
+	connection.DefaultConnection = _default.NewDefaultConnection(connection,
+		_default.WithPlcFieldHandler(fieldHandler),
+		_default.WithPlcValueHandler(NewValueHandler()),
+	)
+	return connection, nil
+}
+
+func (m *Connection) GetConnectionId() string {
+	return m.connectionId
+}
+
+func (m *Connection) IsTraceEnabled() bool {
+	return m.tracer != nil
+}
+
+func (m *Connection) GetTracer() *spi.Tracer {
+	return m.tracer
+}
+
+func (m *Connection) GetConnection() plc4go.PlcConnection {
+	return m
+}
+
+func (m *Connection) GetMessageCodec() spi.MessageCodec {
+	return m.messageCodec
+}
+
+func (m *Connection) GetMetadata() apiModel.PlcConnectionMetadata {
+	return _default.DefaultConnectionMetadata{
+		ProvidesReading:     true,
+		ProvidesWriting:     true,
+		ProvidesSubscribing: true,
+	}
+}
+
+func (m *Connection) ReadRequestBuilder() apiModel.PlcReadRequestBuilder {
+	return internalModel.NewDefaultPlcReadRequestBuilder(m.GetPlcFieldHandler(), m.reader)
+}
+
+func (m *Connection) WriteRequestBuilder() apiModel.PlcWriteRequestBuilder {
+	return internalModel.NewDefaultPlcWriteRequestBuilder(m.GetPlcFieldHandler(), m.GetPlcValueHandler(), m.writer)
+}
+
+func (m *Connection) SubscriptionRequestBuilder() apiModel.PlcSubscriptionRequestBuilder {
+	panic("implement me")
+}
+
+func (m *Connection) UnsubscriptionRequestBuilder() apiModel.PlcUnsubscriptionRequestBuilder {
+	panic("implement me")
+}
+
+func (m *Connection) GetTransportInstance() transports.TransportInstance {
+	if mc, ok := m.messageCodec.(spi.TransportInstanceExposer); ok {
+		return mc.GetTransportInstance()
+	}
+	return nil
+}
+
+func (m *Connection) String() string {
+	return fmt.Sprintf("ads.Connection{}")
+}
diff --git a/plc4go/internal/ads/Driver.go b/plc4go/internal/ads/Driver.go
new file mode 100644
index 0000000000..49c6e6d5da
--- /dev/null
+++ b/plc4go/internal/ads/Driver.go
@@ -0,0 +1,87 @@
+/*
+ * 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 ads
+
+import (
+	_default "github.com/apache/plc4x/plc4go/internal/spi/default"
+	"github.com/apache/plc4x/plc4go/internal/spi/transports"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+	"net/url"
+)
+
+type Driver struct {
+	_default.DefaultDriver
+}
+
+func NewDriver() plc4go.PlcDriver {
+	return &Driver{
+		DefaultDriver: _default.NewDefaultDriver("ads", "Beckhoff TwinCat ADS", "tcp", NewFieldHandler()),
+	}
+}
+
+func (m *Driver) GetConnection(transportUrl url.URL, transports map[string]transports.Transport, options map[string][]string) <-chan plc4go.PlcConnectionConnectResult {
+	log.Debug().Stringer("transportUrl", &transportUrl).Msgf("Get connection for transport url with %d transport(s) and %d option(s)", len(transports), len(options))
+	// Get an the transport specified in the url
+	transport, ok := transports[transportUrl.Scheme]
+	if !ok {
+		log.Error().Stringer("transportUrl", &transportUrl).Msgf("We couldn't find a transport for scheme %s", transportUrl.Scheme)
+		ch := make(chan plc4go.PlcConnectionConnectResult)
+		go func() {
+			ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.Errorf("couldn't find transport for given transport url %#v", transportUrl))
+		}()
+		return ch
+	}
+	// Provide a default-port to the transport, which is used, if the user doesn't provide on in the connection string.
+	options["defaultTcpPort"] = []string{"48898"}
+	// Have the transport create a new transport-instance.
+	transportInstance, err := transport.CreateTransportInstance(transportUrl, options)
+	if err != nil {
+		log.Error().Stringer("transportUrl", &transportUrl).Msgf("We couldn't create a transport instance for port %#v", options["defaultTcpPort"])
+		ch := make(chan plc4go.PlcConnectionConnectResult)
+		ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.New("couldn't initialize transport configuration for given transport url "+transportUrl.String()))
+		return ch
+	}
+
+	// Create a new codec for taking care of encoding/decoding of messages
+	codec := NewMessageCodec(transportInstance)
+	log.Debug().Msgf("working with codec %#v", codec)
+
+	configuration, err := ParseFromOptions(options)
+	if err != nil {
+		log.Error().Err(err).Msgf("Invalid options")
+		ch := make(chan plc4go.PlcConnectionConnectResult)
+		ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.Wrap(err, "invalid configuration"))
+		return ch
+	}
+
+	// Create the new connection
+	connection, err := NewConnection(codec, configuration, m.GetPlcFieldHandler(), options)
+	if err != nil {
+		ch := make(chan plc4go.PlcConnectionConnectResult)
+		go func() {
+			ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.Wrap(err, "couldn't create connection"))
+		}()
+		return ch
+	}
+	log.Debug().Stringer("connection", connection).Msg("created connection, connecting now")
+	return connection.Connect()
+}
diff --git a/plc4go/internal/ads/Field.go b/plc4go/internal/ads/Field.go
new file mode 100644
index 0000000000..6038138d2c
--- /dev/null
+++ b/plc4go/internal/ads/Field.go
@@ -0,0 +1,216 @@
+/*
+ * 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 ads
+
+import (
+	"encoding/xml"
+	"fmt"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+	model2 "github.com/apache/plc4x/plc4go/protocols/ads/readwrite/model"
+	"github.com/pkg/errors"
+)
+
+type PlcField struct {
+	FieldType        FieldType
+	StringLength     int32
+	NumberOfElements uint32
+	Datatype         model2.AdsDataType
+}
+
+func (m PlcField) GetTypeName() string {
+	return m.FieldType.GetName()
+}
+
+func (m PlcField) GetQuantity() uint16 {
+	return uint16(m.NumberOfElements)
+}
+
+func (m PlcField) GetNumberOfElements() uint32 {
+	return m.NumberOfElements
+}
+
+func (m PlcField) GetDatatype() model2.AdsDataType {
+	return m.Datatype
+}
+
+func (m PlcField) GetStringLength() int32 {
+	return m.StringLength
+}
+
+func (m PlcField) GetAddressString() string {
+	return fmt.Sprintf("%dx%05d%05d:%s", m.FieldType, m.StringLength, m.NumberOfElements, m.Datatype.String())
+}
+
+type AdsPlcField interface {
+	GetDatatype() model2.AdsDataType
+	GetStringLength() int32
+	GetNumberOfElements() uint32
+	model.PlcField
+}
+
+func castToAdsFieldFromPlcField(plcField model.PlcField) (AdsPlcField, error) {
+	if adsField, ok := plcField.(AdsPlcField); ok {
+		return adsField, nil
+	}
+	return nil, errors.Errorf("couldn't %T cast to AdsPlcField", plcField)
+}
+
+type DirectPlcField struct {
+	IndexGroup  uint32
+	IndexOffset uint32
+	PlcField
+}
+
+func (m DirectPlcField) GetAddressString() string {
+	return fmt.Sprintf("%dx%05d%05d%05d%05d:%s", m.FieldType, m.IndexGroup, m.IndexOffset, m.StringLength, m.NumberOfElements, m.Datatype.String())
+}
+
+func newDirectAdsPlcField(indexGroup uint32, indexOffset uint32, adsDataType model2.AdsDataType, stringLength int32, numberOfElements uint32) (model.PlcField, error) {
+	fieldType := DirectAdsField
+	if stringLength > 0 {
+		fieldType = DirectAdsStringField
+	}
+	return DirectPlcField{
+		IndexGroup:  indexGroup,
+		IndexOffset: indexOffset,
+		PlcField: PlcField{
+			FieldType:        fieldType,
+			StringLength:     stringLength,
+			NumberOfElements: numberOfElements,
+			Datatype:         adsDataType,
+		},
+	}, nil
+}
+
+func castToDirectAdsFieldFromPlcField(plcField model.PlcField) (DirectPlcField, error) {
+	if adsField, ok := plcField.(DirectPlcField); ok {
+		return adsField, nil
+	}
+	return DirectPlcField{}, errors.Errorf("couldn't %T cast to DirectPlcField", plcField)
+}
+
+func (m DirectPlcField) Serialize(writeBuffer utils.WriteBuffer) error {
+	if err := writeBuffer.PushContext(m.FieldType.GetName()); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.WriteUint32("indexGroup", 32, m.IndexGroup); err != nil {
+		return err
+	}
+	if err := writeBuffer.WriteUint32("indexOffset", 32, m.IndexOffset); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.WriteUint32("numberOfElements", 32, m.NumberOfElements); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.WriteString("dataType", uint32(len([]rune(m.Datatype.String()))*8), "UTF-8", m.Datatype.String()); err != nil {
+		return err
+	}
+
+	if m.StringLength != 0 {
+		if err := writeBuffer.WriteInt32("stringLength", 32, m.StringLength); err != nil {
+			return err
+		}
+	}
+
+	if err := writeBuffer.PopContext(m.FieldType.GetName()); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (m DirectPlcField) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
+	panic(name)
+}
+
+type SymbolicPlcField struct {
+	SymbolicAddress string
+	PlcField
+}
+
+func (m SymbolicPlcField) GetAddressString() string {
+	return fmt.Sprintf("%dx%s%05d%05d:%s", m.FieldType, m.SymbolicAddress, m.StringLength, m.NumberOfElements, m.Datatype.String())
+}
+
+func newAdsSymbolicPlcField(symbolicAddress string, adsDataType model2.AdsDataType, stringLength int32, numberOfElements uint32) (model.PlcField, error) {
+	fieldType := SymbolicAdsField
+	if stringLength > 0 {
+		fieldType = SymbolicAdsStringField
+	}
+	return SymbolicPlcField{
+		SymbolicAddress: symbolicAddress,
+		PlcField: PlcField{
+			FieldType:        fieldType,
+			StringLength:     stringLength,
+			NumberOfElements: numberOfElements,
+			Datatype:         adsDataType,
+		},
+	}, nil
+}
+
+func needsResolving(plcField model.PlcField) bool {
+	switch plcField.(type) {
+	case SymbolicPlcField:
+		return true
+	case DirectPlcField:
+		return false
+	default:
+		return false
+	}
+}
+
+func castToSymbolicPlcFieldFromPlcField(plcField model.PlcField) (SymbolicPlcField, error) {
+	if adsField, ok := plcField.(SymbolicPlcField); ok {
+		return adsField, nil
+	}
+	return SymbolicPlcField{}, errors.Errorf("couldn't cast %T to SymbolicPlcField", plcField)
+}
+
+func (m SymbolicPlcField) Serialize(writeBuffer utils.WriteBuffer) error {
+	if err := writeBuffer.PushContext(m.FieldType.GetName()); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.WriteString("symbolicAddress", uint32(len([]rune(m.SymbolicAddress))*8), "UTF-8", m.SymbolicAddress); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.WriteUint32("numberOfElements", 32, m.NumberOfElements); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.WriteString("dataType", uint32(len([]rune(m.Datatype.String()))*8), "UTF-8", m.Datatype.String()); err != nil {
+		return err
+	}
+
+	if m.StringLength > 0 {
+		if err := writeBuffer.WriteInt32("stringLength", 32, m.StringLength); err != nil {
+			return err
+		}
+	}
+
+	if err := writeBuffer.PopContext(m.FieldType.GetName()); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/plc4go/internal/ads/FieldHandler.go b/plc4go/internal/ads/FieldHandler.go
new file mode 100644
index 0000000000..8224298066
--- /dev/null
+++ b/plc4go/internal/ads/FieldHandler.go
@@ -0,0 +1,162 @@
+/*
+ * 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 ads
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	apiModel "github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+	model2 "github.com/apache/plc4x/plc4go/protocols/ads/readwrite/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+	"regexp"
+	"strconv"
+)
+
+type FieldType uint8
+
+//go:generate stringer -type FieldType
+const (
+	DirectAdsStringField   FieldType = 0x00
+	DirectAdsField         FieldType = 0x01
+	SymbolicAdsStringField FieldType = 0x03
+	SymbolicAdsField       FieldType = 0x04
+)
+
+func (i FieldType) GetName() string {
+	return i.String()
+}
+
+type FieldHandler struct {
+	directAdsStringField   *regexp.Regexp
+	directAdsField         *regexp.Regexp
+	symbolicAdsStringField *regexp.Regexp
+	symbolicAdsField       *regexp.Regexp
+}
+
+func NewFieldHandler() FieldHandler {
+	return FieldHandler{
+		directAdsStringField:   regexp.MustCompile(`^((0[xX](?P<indexGroupHex>[0-9a-fA-F]+))|(?P<indexGroup>\d+))/((0[xX](?P<indexOffsetHex>[0-9a-fA-F]+))|(?P<indexOffset>\d+)):(?P<adsDataType>STRING|WSTRING)\((?P<stringLength>\d{1,3})\)(\[(?P<numberOfElements>\d+)])?`),
+		directAdsField:         regexp.MustCompile(`^((0[xX](?P<indexGroupHex>[0-9a-fA-F]+))|(?P<indexGroup>\d+))/((0[xX](?P<indexOffsetHex>[0-9a-fA-F]+))|(?P<indexOffset>\d+)):(?P<adsDataType>\w+)(\[(?P<numberOfElements>\d+)])?`),
+		symbolicAdsStringField: regexp.MustCompile(`^(?P<symbolicAddress>.+):(?P<adsDataType>'STRING'|'WSTRING')\((?P<stringLength>\d{1,3})\)(\[(?P<numberOfElements>\d+)])?`),
+		symbolicAdsField:       regexp.MustCompile(`^(?P<symbolicAddress>.+):(?P<adsDataType>\w+)(\[(?P<numberOfElements>\d+)])?`),
+	}
+}
+
+func (m FieldHandler) ParseQuery(query string) (apiModel.PlcField, error) {
+	if match := utils.GetSubgroupMatches(m.directAdsStringField, query); match != nil {
+		var indexGroup uint32
+		if indexGroupHexString := match["indexGroupHex"]; indexGroupHexString != "" {
+			decodeString, err := hex.DecodeString(indexGroupHexString[2:])
+			if err != nil {
+				return nil, errors.Wrap(err, "Error decoding index group")
+			}
+			indexGroup = binary.BigEndian.Uint32(decodeString)
+		} else {
+			parsedIndexGroup, err := strconv.ParseUint(match["indexGroup"], 10, 32)
+			if err != nil {
+				return nil, errors.Wrap(err, "Error decoding index group")
+			}
+			indexGroup = uint32(parsedIndexGroup)
+		}
+		var indexOffset uint32
+		if indexOffsetHexString := match["indexOffsetHex"]; indexOffsetHexString != "" {
+			decodeString, err := hex.DecodeString(indexOffsetHexString[2:])
+			if err != nil {
+				return nil, errors.Wrap(err, "Error decoding index group")
+			}
+			indexOffset = binary.BigEndian.Uint32(decodeString)
+		} else {
+			parsedIndexOffset, err := strconv.ParseUint(match["indexOffset"], 10, 32)
+			if err != nil {
+				return nil, errors.Wrap(err, "Error decoding index group")
+			}
+			indexOffset = uint32(parsedIndexOffset)
+		}
+		stringLength, err := strconv.ParseInt(match["stringLength"], 10, 32)
+		if err != nil {
+			return nil, errors.Wrap(err, "Error decoding string length")
+		}
+		numberOfElements, err := strconv.ParseUint(match["numberOfElements"], 10, 32)
+		if err != nil {
+			log.Trace().Msg("Falling back to number of elements 1")
+			numberOfElements = 1
+		}
+
+		return newDirectAdsPlcField(indexGroup, indexOffset, model2.AdsDataTypeByName(match["adsDataType"]), int32(stringLength), uint32(numberOfElements))
+	} else if match := utils.GetSubgroupMatches(m.directAdsField, query); match != nil {
+		var indexGroup uint32
+		if indexGroupHexString := match["indexGroupHex"]; indexGroupHexString != "" {
+			decodeString, err := hex.DecodeString(indexGroupHexString[2:])
+			if err != nil {
+				return nil, errors.Wrap(err, "Error decoding index group")
+			}
+			indexGroup = binary.BigEndian.Uint32(decodeString)
+		} else {
+			parsedIndexGroup, err := strconv.ParseUint(match["indexGroup"], 10, 32)
+			if err != nil {
+				return nil, errors.Wrap(err, "Error decoding index group")
+			}
+			indexGroup = uint32(parsedIndexGroup)
+		}
+		var indexOffset uint32
+		if indexOffsetHexString := match["indexOffsetHex"]; indexOffsetHexString != "" {
+			decodeString, err := hex.DecodeString(indexOffsetHexString[2:])
+			if err != nil {
+				return nil, errors.Wrap(err, "Error decoding index group")
+			}
+			indexOffset = binary.BigEndian.Uint32(decodeString)
+		} else {
+			parsedIndexOffset, err := strconv.ParseUint(match["indexOffset"], 10, 32)
+			if err != nil {
+				return nil, errors.Wrap(err, "Error decoding index group")
+			}
+			indexOffset = uint32(parsedIndexOffset)
+		}
+
+		adsDataType := model2.AdsDataTypeByName(match["adsDataType"])
+		numberOfElements, err := strconv.ParseUint(match["numberOfElements"], 10, 32)
+		if err != nil {
+			log.Trace().Msg("Falling back to number of elements 1")
+			numberOfElements = 1
+		}
+		return newDirectAdsPlcField(indexGroup, indexOffset, adsDataType, int32(0), uint32(numberOfElements))
+	} else if match := utils.GetSubgroupMatches(m.symbolicAdsStringField, query); match != nil {
+		stringLength, err := strconv.ParseInt(match["stringLength"], 10, 32)
+		if err != nil {
+			return nil, errors.Wrap(err, "Error decoding string length")
+		}
+		numberOfElements, err := strconv.ParseUint(match["numberOfElements"], 10, 32)
+		if err != nil {
+			return nil, errors.Wrap(err, "Error decoding number of elements")
+		}
+		return newAdsSymbolicPlcField(match["symbolicAddress"], model2.AdsDataTypeByName(match["adsDataType"]), int32(stringLength), uint32(numberOfElements))
+	} else if match := utils.GetSubgroupMatches(m.symbolicAdsField, query); match != nil {
+		numberOfElements, err := strconv.ParseUint(match["numberOfElements"], 10, 32)
+		if err != nil {
+			log.Trace().Msg("Falling back to number of elements 1")
+			numberOfElements = 1
+		}
+		return newAdsSymbolicPlcField(match["symbolicAddress"], model2.AdsDataTypeByName(match["adsDataType"]), int32(0), uint32(numberOfElements))
+	} else {
+		return nil, errors.Errorf("Invalid address format for address '%s'", query)
+	}
+}
diff --git a/plc4go/internal/ads/MessageCodec.go b/plc4go/internal/ads/MessageCodec.go
new file mode 100644
index 0000000000..7118d8e4bb
--- /dev/null
+++ b/plc4go/internal/ads/MessageCodec.go
@@ -0,0 +1,101 @@
+/*
+ * 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 ads
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	"github.com/apache/plc4x/plc4go/internal/spi/default"
+	"github.com/apache/plc4x/plc4go/internal/spi/transports"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/apache/plc4x/plc4go/protocols/ads/readwrite/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+)
+
+type MessageCodec struct {
+	_default.DefaultCodec
+}
+
+func NewMessageCodec(transportInstance transports.TransportInstance) *MessageCodec {
+	codec := &MessageCodec{}
+	codec.DefaultCodec = _default.NewDefaultCodec(codec, transportInstance)
+	return codec
+}
+
+func (m *MessageCodec) GetCodec() spi.MessageCodec {
+	return m
+}
+
+func (m *MessageCodec) Send(message interface{}) error {
+	log.Trace().Msg("Sending message")
+	// Cast the message to the correct type of struct
+	tcpPaket := model.CastAmsTCPPacket(message)
+	// Serialize the request
+	wb := utils.NewLittleEndianWriteBufferByteBased()
+	err := tcpPaket.Serialize(wb)
+	if err != nil {
+		return errors.Wrap(err, "error serializing request")
+	}
+
+	// Send it to the PLC
+	err = m.GetTransportInstance().Write(wb.GetBytes())
+	if err != nil {
+		return errors.Wrap(err, "error sending request")
+	}
+	return nil
+}
+
+func (m *MessageCodec) Receive() (interface{}, error) {
+	log.Trace().Msg("receiving")
+	// We need at least 6 bytes in order to know how big the packet is in total
+	if num, err := m.GetTransportInstance().GetNumReadableBytes(); (err == nil) && (num >= 6) {
+		log.Debug().Msgf("we got %d readable bytes", num)
+		data, err := m.GetTransportInstance().PeekReadableBytes(6)
+		if err != nil {
+			log.Warn().Err(err).Msg("error peeking")
+			// TODO: Possibly clean up ...
+			return nil, nil
+		}
+		// Get the size of the entire packet little endian plus size of header
+		packetSize := (uint32(data[5]) << 24) + (uint32(data[4]) << 16) + (uint32(data[3]) << 8) + (uint32(data[2])) + 6
+		if num < packetSize {
+			log.Debug().Msgf("Not enough bytes. Got: %d Need: %d\n", num, packetSize)
+			return nil, nil
+		}
+		data, err = m.GetTransportInstance().Read(packetSize)
+		if err != nil {
+			// TODO: Possibly clean up ...
+			return nil, nil
+		}
+		rb := utils.NewLittleEndianReadBufferByteBased(data)
+		tcpPacket, err := model.AmsTCPPacketParse(rb)
+		if err != nil {
+			log.Warn().Err(err).Msg("error parsing")
+			// TODO: Possibly clean up ...
+			return nil, nil
+		}
+		return tcpPacket, nil
+	} else if err != nil {
+		log.Warn().Err(err).Msg("Got error reading")
+		return nil, nil
+	}
+	// TODO: maybe we return here a not enough error error
+	return nil, nil
+}
diff --git a/plc4go/internal/ads/Reader.go b/plc4go/internal/ads/Reader.go
new file mode 100644
index 0000000000..8be51b2131
--- /dev/null
+++ b/plc4go/internal/ads/Reader.go
@@ -0,0 +1,432 @@
+/*
+ * 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 ads
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	plc4goModel "github.com/apache/plc4x/plc4go/internal/spi/model"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go/values"
+	readWriteModel "github.com/apache/plc4x/plc4go/protocols/ads/readwrite/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+	"math"
+	"sync"
+	"sync/atomic"
+	"time"
+)
+
+type Reader struct {
+	transactionIdentifier uint32
+	targetAmsNetId        readWriteModel.AmsNetId
+	targetAmsPort         uint16
+	sourceAmsNetId        readWriteModel.AmsNetId
+	sourceAmsPort         uint16
+	messageCodec          spi.MessageCodec
+	fieldMapping          map[SymbolicPlcField]DirectPlcField
+	mappingLock           sync.Mutex
+}
+
+func NewReader(messageCodec spi.MessageCodec, targetAmsNetId readWriteModel.AmsNetId, targetAmsPort uint16, sourceAmsNetId readWriteModel.AmsNetId, sourceAmsPort uint16) *Reader {
+	return &Reader{
+		transactionIdentifier: 0,
+		targetAmsNetId:        targetAmsNetId,
+		targetAmsPort:         targetAmsPort,
+		sourceAmsNetId:        sourceAmsNetId,
+		sourceAmsPort:         sourceAmsPort,
+		messageCodec:          messageCodec,
+		fieldMapping:          make(map[SymbolicPlcField]DirectPlcField),
+	}
+}
+
+func (m *Reader) Read(readRequest model.PlcReadRequest) <-chan model.PlcReadRequestResult {
+	log.Trace().Msg("Reading")
+	result := make(chan model.PlcReadRequestResult)
+	go func() {
+		if len(readRequest.GetFieldNames()) <= 1 {
+			m.singleRead(readRequest, result)
+		} else {
+			m.multiRead(readRequest, result)
+		}
+	}()
+	return result
+}
+
+func (m *Reader) singleRead(readRequest model.PlcReadRequest, result chan model.PlcReadRequestResult) {
+	if len(readRequest.GetFieldNames()) != 1 {
+		result <- &plc4goModel.DefaultPlcReadRequestResult{
+			Request:  readRequest,
+			Response: nil,
+			Err:      errors.New("ads only supports single-item requests"),
+		}
+		log.Debug().Msgf("ads only supports single-item requests. Got %d fields", len(readRequest.GetFieldNames()))
+		return
+	}
+	// If we are requesting only one field, use a
+	fieldName := readRequest.GetFieldNames()[0]
+	field := readRequest.GetField(fieldName)
+	if needsResolving(field) {
+		adsField, err := castToSymbolicPlcFieldFromPlcField(field)
+		if err != nil {
+			result <- &plc4goModel.DefaultPlcReadRequestResult{
+				Request:  readRequest,
+				Response: nil,
+				Err:      errors.Wrap(err, "invalid field item type"),
+			}
+			log.Debug().Msgf("Invalid field item type %T", field)
+			return
+		}
+		field, err = m.resolveField(adsField)
+		if err != nil {
+			result <- &plc4goModel.DefaultPlcReadRequestResult{
+				Request:  readRequest,
+				Response: nil,
+				Err:      errors.Wrap(err, "invalid field item type"),
+			}
+			log.Debug().Msgf("Invalid field item type %T", field)
+			return
+		}
+	}
+	adsField, err := castToDirectAdsFieldFromPlcField(field)
+	if err != nil {
+		result <- &plc4goModel.DefaultPlcReadRequestResult{
+			Request:  readRequest,
+			Response: nil,
+			Err:      errors.Wrap(err, "invalid field item type"),
+		}
+		log.Debug().Msgf("Invalid field item type %T", field)
+		return
+	}
+	userdata := readWriteModel.AmsPacket{
+		TargetAmsNetId: &m.targetAmsNetId,
+		TargetAmsPort:  m.targetAmsPort,
+		SourceAmsNetId: &m.sourceAmsNetId,
+		SourceAmsPort:  m.sourceAmsPort,
+		CommandId:      readWriteModel.CommandId_ADS_READ,
+		State:          readWriteModel.NewState(false, false, false, false, false, true, false, false, false),
+		ErrorCode:      0,
+		InvokeId:       0,
+		Data:           nil,
+	}
+
+	readLength := uint32(adsField.Datatype.NumBytes())
+	switch {
+	case adsField.GetDatatype() == readWriteModel.AdsDataType_STRING:
+		// If an explicit size is given with the string, use this, if not use 256
+		if adsField.GetStringLength() != 0 {
+			readLength = uint32(adsField.GetStringLength())
+		} else {
+			readLength = 256
+		}
+	case adsField.GetDatatype() == readWriteModel.AdsDataType_WSTRING:
+		// If an explicit size is given with the string, use this, if not use 512
+		if adsField.GetStringLength() != 0 {
+			readLength = uint32(adsField.GetStringLength() * 2)
+		} else {
+			readLength = 512
+		}
+	default:
+		readLength = uint32(adsField.Datatype.NumBytes())
+	}
+	userdata.Data = readWriteModel.NewAdsReadRequest(adsField.IndexGroup, adsField.IndexOffset, readLength).GetParent()
+
+	m.sendOverTheWire(userdata, readRequest, result)
+}
+
+func (m *Reader) multiRead(readRequest model.PlcReadRequest, result chan model.PlcReadRequestResult) {
+	// Calculate the size of all fields together.
+	// Calculate the expected size of the response data.
+	expectedResponseDataSize := uint32(0)
+	for _, fieldName := range readRequest.GetFieldNames() {
+		field, err := castToAdsFieldFromPlcField(readRequest.GetField(fieldName))
+		if err != nil {
+			result <- &plc4goModel.DefaultPlcReadRequestResult{
+				Request:  readRequest,
+				Response: nil,
+				Err:      errors.Wrap(err, "error casting field"),
+			}
+			return
+		}
+		size := uint32(0)
+		switch field.GetDatatype() {
+		case readWriteModel.AdsDataType_STRING:
+			// If an explicit size is given with the string, use this, if not use 256
+			if field.GetStringLength() != 0 {
+				size = uint32(field.GetStringLength())
+			} else {
+				size = 256
+			}
+		case readWriteModel.AdsDataType_WSTRING:
+			// If an explicit size is given with the string, use this, if not use 512
+			if field.GetStringLength() != 0 {
+				size = uint32(field.GetStringLength() * 2)
+			} else {
+				size = 512
+			}
+		default:
+			size = uint32(field.GetDatatype().NumBytes())
+		}
+		// Status code + payload size
+		expectedResponseDataSize += 4 + (size * field.GetNumberOfElements())
+	}
+
+	userdata := readWriteModel.AmsPacket{
+		TargetAmsNetId: &m.targetAmsNetId,
+		TargetAmsPort:  m.targetAmsPort,
+		SourceAmsNetId: &m.sourceAmsNetId,
+		SourceAmsPort:  m.sourceAmsPort,
+		CommandId:      readWriteModel.CommandId_ADS_READ_WRITE,
+		State:          readWriteModel.NewState(false, false, false, false, false, true, false, false, false),
+		ErrorCode:      0,
+		InvokeId:       0,
+		Data:           nil,
+	}
+
+	items := make([]*readWriteModel.AdsMultiRequestItem, len(readRequest.GetFieldNames()))
+	for i, fieldName := range readRequest.GetFieldNames() {
+		field := readRequest.GetField(fieldName)
+		if needsResolving(field) {
+			adsField, err := castToSymbolicPlcFieldFromPlcField(field)
+			if err != nil {
+				result <- &plc4goModel.DefaultPlcReadRequestResult{
+					Request:  readRequest,
+					Response: nil,
+					Err:      errors.Wrap(err, "invalid field item type"),
+				}
+				log.Debug().Msgf("Invalid field item type %T", field)
+				return
+			}
+			field, err = m.resolveField(adsField)
+			if err != nil {
+				result <- &plc4goModel.DefaultPlcReadRequestResult{
+					Request:  readRequest,
+					Response: nil,
+					Err:      errors.Wrap(err, "invalid field item type"),
+				}
+				log.Debug().Msgf("Invalid field item type %T", field)
+				return
+			}
+		}
+		adsField, err := castToDirectAdsFieldFromPlcField(field)
+		if err != nil {
+			result <- &plc4goModel.DefaultPlcReadRequestResult{
+				Request:  readRequest,
+				Response: nil,
+				Err:      errors.Wrap(err, "invalid field item type"),
+			}
+			log.Debug().Msgf("Invalid field item type %T", field)
+			return
+		}
+		// With multi-requests, the index-group is fixed and the index offset indicates the number of elements.
+		items[i] = readWriteModel.NewAdsMultiRequestItemRead(adsField.IndexGroup, adsField.IndexOffset, uint32(adsField.GetDatatype().NumBytes())*adsField.NumberOfElements).GetParent()
+	}
+	userdata.Data = readWriteModel.NewAdsReadWriteRequest(uint32(readWriteModel.ReservedIndexGroups_ADSIGRP_MULTIPLE_READ), uint32(len(readRequest.GetFieldNames())), expectedResponseDataSize, items, nil).GetParent()
+
+	m.sendOverTheWire(userdata, readRequest, result)
+}
+
+func (m *Reader) sendOverTheWire(userdata readWriteModel.AmsPacket, readRequest model.PlcReadRequest, result chan model.PlcReadRequestResult) {
+	// Calculate a new transaction identifier
+	transactionIdentifier := atomic.AddUint32(&m.transactionIdentifier, 1)
+	if transactionIdentifier > math.MaxUint8 {
+		transactionIdentifier = 1
+		atomic.StoreUint32(&m.transactionIdentifier, 1)
+	}
+	log.Debug().Msgf("Calculated transaction identifier %x", transactionIdentifier)
+	userdata.InvokeId = transactionIdentifier
+
+	// Assemble the finished tcp paket
+	log.Trace().Msg("Assemble tcp paket")
+	amsTcpPaket := readWriteModel.AmsTCPPacket{
+		Userdata: &userdata,
+	}
+
+	// Send the TCP Paket over the wire
+	log.Trace().Msg("Send TCP Paket")
+	if err := m.messageCodec.SendRequest(
+		amsTcpPaket,
+		func(message interface{}) bool {
+			paket := readWriteModel.CastAmsTCPPacket(message)
+			return paket.Userdata.InvokeId == transactionIdentifier
+		},
+		func(message interface{}) error {
+			// Convert the response into an amsTcpPaket
+			log.Trace().Msg("convert response to amsTcpPaket")
+			amsTcpPaket := readWriteModel.CastAmsTCPPacket(message)
+			// Convert the ads response into a PLC4X response
+			log.Trace().Msg("convert response to PLC4X response")
+			readResponse, err := m.ToPlc4xReadResponse(*amsTcpPaket, readRequest)
+
+			if err != nil {
+				result <- &plc4goModel.DefaultPlcReadRequestResult{
+					Request: readRequest,
+					Err:     errors.Wrap(err, "Error decoding response"),
+				}
+				// TODO: should we return the error here?
+				return nil
+			}
+			result <- &plc4goModel.DefaultPlcReadRequestResult{
+				Request:  readRequest,
+				Response: readResponse,
+			}
+			return nil
+		},
+		func(err error) error {
+			result <- &plc4goModel.DefaultPlcReadRequestResult{
+				Request: readRequest,
+				Err:     errors.Wrap(err, "got timeout while waiting for response"),
+			}
+			return nil
+		},
+		time.Second*1); err != nil {
+		result <- &plc4goModel.DefaultPlcReadRequestResult{
+			Request:  readRequest,
+			Response: nil,
+			Err:      errors.Wrap(err, "error sending message"),
+		}
+	}
+}
+
+func (m *Reader) resolveField(symbolicField SymbolicPlcField) (DirectPlcField, error) {
+	if directPlcField, ok := m.fieldMapping[symbolicField]; ok {
+		return directPlcField, nil
+	}
+	m.mappingLock.Lock()
+	defer m.mappingLock.Unlock()
+	// In case a previous one has already
+	if directPlcField, ok := m.fieldMapping[symbolicField]; ok {
+		return directPlcField, nil
+	}
+	userdata := readWriteModel.AmsPacket{
+		TargetAmsNetId: &m.targetAmsNetId,
+		TargetAmsPort:  m.targetAmsPort,
+		SourceAmsNetId: &m.sourceAmsNetId,
+		SourceAmsPort:  m.sourceAmsPort,
+		CommandId:      readWriteModel.CommandId_ADS_READ_WRITE,
+		State:          readWriteModel.NewState(false, false, false, false, false, true, false, false, false),
+		ErrorCode:      0,
+		InvokeId:       0,
+		Data:           nil,
+	}
+	userdata.Data = readWriteModel.NewAdsReadWriteRequest(
+		uint32(readWriteModel.ReservedIndexGroups_ADSIGRP_SYM_HNDBYNAME),
+		0,
+		4,
+		nil,
+		[]byte(symbolicField.SymbolicAddress+"\000"),
+	).GetParent()
+	result := make(chan model.PlcReadRequestResult)
+	go func() {
+		dummyRequest := plc4goModel.NewDefaultPlcReadRequest(map[string]model.PlcField{"dummy": DirectPlcField{PlcField: PlcField{Datatype: readWriteModel.AdsDataType_UINT32}}}, []string{"dummy"}, nil, nil)
+		m.sendOverTheWire(userdata, dummyRequest, result)
+	}()
+	// We wait synchronous for the resolution response before we can continue
+	response := <-result
+	if response.GetErr() != nil {
+		log.Debug().Err(response.GetErr()).Msg("Error during resolve")
+		return DirectPlcField{}, response.GetErr()
+	}
+	if response.GetResponse().GetResponseCode("dummy") != model.PlcResponseCode_OK {
+		return DirectPlcField{}, errors.Errorf("Got a response error %#v", response.GetResponse().GetResponseCode("dummy"))
+	}
+	handle := response.GetResponse().GetValue("dummy").GetUint32()
+	log.Debug().Uint32("handle", handle).Str("symbolicAddress", symbolicField.SymbolicAddress).Msg("Resolved symbolic address")
+	directPlcField := DirectPlcField{
+		IndexGroup:  uint32(readWriteModel.ReservedIndexGroups_ADSIGRP_SYM_VALBYHND),
+		IndexOffset: handle,
+		PlcField:    symbolicField.PlcField,
+	}
+	switch directPlcField.FieldType {
+	case SymbolicAdsField:
+		directPlcField.FieldType = DirectAdsField
+	case SymbolicAdsStringField:
+		directPlcField.FieldType = DirectAdsStringField
+	}
+	m.fieldMapping[symbolicField] = directPlcField
+	return directPlcField, nil
+}
+
+func (m *Reader) ToPlc4xReadResponse(amsTcpPaket readWriteModel.AmsTCPPacket, readRequest model.PlcReadRequest) (model.PlcReadResponse, error) {
+	var rb utils.ReadBuffer
+	responseCodes := map[string]model.PlcResponseCode{}
+	switch amsTcpPaket.Userdata.Data.Child.(type) {
+	case *readWriteModel.AdsReadResponse:
+		readResponse := readWriteModel.CastAdsReadResponse(amsTcpPaket.Userdata.Data)
+		data := readResponse.Data
+		rb = utils.NewLittleEndianReadBufferByteBased(data)
+		for _, fieldName := range readRequest.GetFieldNames() {
+			responseCodes[fieldName] = model.PlcResponseCode_OK
+		}
+	case *readWriteModel.AdsReadWriteResponse:
+		readResponse := readWriteModel.CastAdsReadWriteResponse(amsTcpPaket.Userdata.Data)
+		data := readResponse.Data
+		rb = utils.NewLittleEndianReadBufferByteBased(data)
+		// When parsing a multi-item response, the error codes of each items come
+		// in sequence and then come the values.
+		for _, fieldName := range readRequest.GetFieldNames() {
+			if len(readRequest.GetFieldNames()) <= 1 {
+				// TODO: the comment above seems strange as there is no such spec for response codes per field so maybe this is a speciality
+				break
+			}
+			responseCode, err := rb.ReadUint32("responseCode", 32)
+			if err != nil {
+				log.Error().Err(err).Str("fieldName", fieldName).Msgf("Error parsing field %s", fieldName)
+				responseCodes[fieldName] = model.PlcResponseCode_INTERNAL_ERROR
+				continue
+			}
+			switch readWriteModel.ReturnCodeByValue(responseCode) {
+			case readWriteModel.ReturnCode_OK:
+				responseCodes[fieldName] = model.PlcResponseCode_OK
+			default:
+				// TODO: Implement this a little more ...
+				log.Error().Stringer("adsReturnCode", readWriteModel.ReturnCodeByValue(responseCode)).Msgf("Unmapped return code for %s", fieldName)
+				responseCodes[fieldName] = model.PlcResponseCode_INTERNAL_ERROR
+			}
+		}
+	default:
+		return nil, errors.Errorf("unsupported response type %T", amsTcpPaket.Userdata.Data.Child)
+	}
+
+	plcValues := map[string]values.PlcValue{}
+	// Get the field from the request
+	for _, fieldName := range readRequest.GetFieldNames() {
+		log.Debug().Msgf("get a field from request with name %s", fieldName)
+		field, err := castToAdsFieldFromPlcField(readRequest.GetField(fieldName))
+		if err != nil {
+			return nil, errors.Wrap(err, "error casting to ads-field")
+		}
+
+		// Decode the data according to the information from the request
+		log.Trace().Msg("decode data")
+		value, err := readWriteModel.DataItemParse(rb, field.GetDatatype().DataFormatName(), field.GetStringLength())
+		if err != nil {
+			log.Error().Err(err).Msg("Error parsing data item")
+			responseCodes[fieldName] = model.PlcResponseCode_INTERNAL_ERROR
+			continue
+		}
+		plcValues[fieldName] = value
+		responseCodes[fieldName] = model.PlcResponseCode_OK
+	}
+
+	// Return the response
+	log.Trace().Msg("Returning the response")
+	return plc4goModel.NewDefaultPlcReadResponse(readRequest, responseCodes, plcValues), nil
+}
diff --git a/plc4go/internal/ads/ValueHandler.go b/plc4go/internal/ads/ValueHandler.go
new file mode 100644
index 0000000000..5cef9a0002
--- /dev/null
+++ b/plc4go/internal/ads/ValueHandler.go
@@ -0,0 +1,32 @@
+/*
+ * 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 ads
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi/values"
+)
+
+type ValueHandler struct {
+	values.IEC61131ValueHandler
+}
+
+func NewValueHandler() ValueHandler {
+	return ValueHandler{}
+}
diff --git a/plc4go/internal/ads/Writer.go b/plc4go/internal/ads/Writer.go
new file mode 100644
index 0000000000..24c24b309c
--- /dev/null
+++ b/plc4go/internal/ads/Writer.go
@@ -0,0 +1,216 @@
+/*
+ * 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 ads
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	plc4goModel "github.com/apache/plc4x/plc4go/internal/spi/model"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+	readWriteModel "github.com/apache/plc4x/plc4go/protocols/ads/readwrite/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+	"math"
+	"sync/atomic"
+	"time"
+)
+
+type Writer struct {
+	transactionIdentifier uint32
+	targetAmsNetId        readWriteModel.AmsNetId
+	targetAmsPort         uint16
+	sourceAmsNetId        readWriteModel.AmsNetId
+	sourceAmsPort         uint16
+	messageCodec          spi.MessageCodec
+	reader                *Reader
+}
+
+func NewWriter(messageCodec spi.MessageCodec, targetAmsNetId readWriteModel.AmsNetId, targetAmsPort uint16, sourceAmsNetId readWriteModel.AmsNetId, sourceAmsPort uint16, reader *Reader) *Writer {
+	return &Writer{
+		transactionIdentifier: 0,
+		targetAmsNetId:        targetAmsNetId,
+		targetAmsPort:         targetAmsPort,
+		sourceAmsNetId:        sourceAmsNetId,
+		sourceAmsPort:         sourceAmsPort,
+		messageCodec:          messageCodec,
+		reader:                reader,
+	}
+}
+
+func (m *Writer) Write(writeRequest model.PlcWriteRequest) <-chan model.PlcWriteRequestResult {
+	result := make(chan model.PlcWriteRequestResult)
+	go func() {
+		// If we are requesting only one field, use a
+		if len(writeRequest.GetFieldNames()) != 1 {
+			result <- &plc4goModel.DefaultPlcWriteRequestResult{
+				Request:  writeRequest,
+				Response: nil,
+				Err:      errors.New("ads only supports single-item requests"),
+			}
+			return
+		}
+		fieldName := writeRequest.GetFieldNames()[0]
+
+		// Get the ads field instance from the request
+		field := writeRequest.GetField(fieldName)
+		if needsResolving(field) {
+			adsField, err := castToSymbolicPlcFieldFromPlcField(field)
+			if err != nil {
+				result <- &plc4goModel.DefaultPlcWriteRequestResult{
+					Request:  writeRequest,
+					Response: nil,
+					Err:      errors.Wrap(err, "invalid field item type"),
+				}
+				log.Debug().Msgf("Invalid field item type %T", field)
+				return
+			}
+			field, err = m.reader.resolveField(adsField)
+			if err != nil {
+				result <- &plc4goModel.DefaultPlcWriteRequestResult{
+					Request:  writeRequest,
+					Response: nil,
+					Err:      errors.Wrap(err, "invalid field item type"),
+				}
+				log.Debug().Msgf("Invalid field item type %T", field)
+				return
+			}
+		}
+		adsField, err := castToDirectAdsFieldFromPlcField(field)
+		if err != nil {
+			result <- &plc4goModel.DefaultPlcWriteRequestResult{
+				Request:  writeRequest,
+				Response: nil,
+				Err:      errors.Wrap(err, "invalid field item type"),
+			}
+			return
+		}
+
+		// Get the value from the request and serialize it to a byte array
+		value := writeRequest.GetValue(fieldName)
+		io := utils.NewLittleEndianWriteBufferByteBased()
+		if err := readWriteModel.DataItemSerialize(io, value, adsField.Datatype.DataFormatName(), adsField.StringLength); err != nil {
+			result <- &plc4goModel.DefaultPlcWriteRequestResult{
+				Request:  writeRequest,
+				Response: nil,
+				Err:      errors.Wrap(err, "error serializing value"),
+			}
+			return
+		}
+		data := io.GetBytes()
+
+		userdata := readWriteModel.AmsPacket{
+			TargetAmsNetId: &m.targetAmsNetId,
+			TargetAmsPort:  m.targetAmsPort,
+			SourceAmsNetId: &m.sourceAmsNetId,
+			SourceAmsPort:  m.sourceAmsPort,
+			CommandId:      readWriteModel.CommandId_ADS_READ,
+			State:          readWriteModel.NewState(false, false, false, false, false, true, false, false, false),
+			ErrorCode:      0,
+			InvokeId:       0,
+			Data:           nil,
+		}
+		switch adsField.FieldType {
+		case DirectAdsStringField:
+			userdata.Data = readWriteModel.NewAdsWriteRequest(adsField.IndexGroup, adsField.IndexOffset, data).GetParent()
+			panic("implement me")
+		case DirectAdsField:
+			panic("implement me")
+		case SymbolicAdsStringField, SymbolicAdsField:
+			panic("we should never reach this point as symbols are resolved before")
+		default:
+			result <- &plc4goModel.DefaultPlcWriteRequestResult{
+				Request:  writeRequest,
+				Response: nil,
+				Err:      errors.New("unsupported field type"),
+			}
+			return
+		}
+
+		// Calculate a new unit identifier
+		// TODO: this is not threadsafe as the whole operation is not atomic
+		transactionIdentifier := atomic.AddUint32(&m.transactionIdentifier, 1)
+		if transactionIdentifier > math.MaxUint8 {
+			transactionIdentifier = 0
+			atomic.StoreUint32(&m.transactionIdentifier, 0)
+		}
+		userdata.InvokeId = transactionIdentifier
+
+		// Assemble the finished amsTcpPaket
+		log.Trace().Msg("Assemble amsTcpPaket")
+		amsTcpPaket := readWriteModel.AmsTCPPacket{
+			Userdata: &userdata,
+		}
+
+		// Send the TCP Paket over the wire
+		err = m.messageCodec.SendRequest(
+			amsTcpPaket,
+			func(message interface{}) bool {
+				paket := readWriteModel.CastAmsTCPPacket(message)
+				return paket.Userdata.InvokeId == transactionIdentifier
+			},
+			func(message interface{}) error {
+				// Convert the response into an responseAmsTcpPaket
+				responseAmsTcpPaket := readWriteModel.CastAmsTCPPacket(message)
+				// Convert the ads response into a PLC4X response
+				readResponse, err := m.ToPlc4xWriteResponse(amsTcpPaket, *responseAmsTcpPaket, writeRequest)
+
+				if err != nil {
+					result <- &plc4goModel.DefaultPlcWriteRequestResult{
+						Request: writeRequest,
+						Err:     errors.Wrap(err, "Error decoding response"),
+					}
+				} else {
+					result <- &plc4goModel.DefaultPlcWriteRequestResult{
+						Request:  writeRequest,
+						Response: readResponse,
+					}
+				}
+				return nil
+			},
+			func(err error) error {
+				result <- &plc4goModel.DefaultPlcWriteRequestResult{
+					Request: writeRequest,
+					Err:     errors.New("got timeout while waiting for response"),
+				}
+				return nil
+			},
+			time.Second*1)
+	}()
+	return result
+}
+
+func (m *Writer) ToPlc4xWriteResponse(requestTcpPaket readWriteModel.AmsTCPPacket, responseTcpPaket readWriteModel.AmsTCPPacket, writeRequest model.PlcWriteRequest) (model.PlcWriteResponse, error) {
+	responseCodes := map[string]model.PlcResponseCode{}
+	fieldName := writeRequest.GetFieldNames()[0]
+
+	// we default to an error until its proven wrong
+	responseCodes[fieldName] = model.PlcResponseCode_INTERNAL_ERROR
+	switch responseTcpPaket.Userdata.Data.Child.(type) {
+	case *readWriteModel.AdsWriteResponse:
+		resp := readWriteModel.CastAdsWriteResponse(responseTcpPaket.Userdata.Data)
+		responseCodes[fieldName] = model.PlcResponseCode(resp.Result)
+	default:
+		return nil, errors.Errorf("unsupported response type %T", responseTcpPaket.Userdata.Data.Child)
+	}
+
+	// Return the response
+	log.Trace().Msg("Returning the response")
+	return plc4goModel.NewDefaultPlcWriteResponse(writeRequest, responseCodes), nil
+}
diff --git a/plc4go/internal/plc4go/ads/fieldtype_string.go b/plc4go/internal/ads/fieldtype_string.go
similarity index 100%
rename from plc4go/internal/plc4go/ads/fieldtype_string.go
rename to plc4go/internal/ads/fieldtype_string.go
diff --git a/plc4go/internal/bacnetip/Connection.go b/plc4go/internal/bacnetip/Connection.go
new file mode 100644
index 0000000000..722fc0a10d
--- /dev/null
+++ b/plc4go/internal/bacnetip/Connection.go
@@ -0,0 +1,118 @@
+/*
+ * 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 bacnetip
+
+import (
+	"fmt"
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	"github.com/apache/plc4x/plc4go/internal/spi/default"
+	internalModel "github.com/apache/plc4x/plc4go/internal/spi/model"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+	"github.com/rs/zerolog/log"
+)
+
+type Connection struct {
+	_default.DefaultConnection
+	messageCodec spi.MessageCodec
+	subscribers  []*Subscriber
+	connectionId string
+	tracer       *spi.Tracer
+}
+
+func NewConnection(messageCodec spi.MessageCodec, fieldHandler spi.PlcFieldHandler, options map[string][]string) *Connection {
+	connection := &Connection{
+		messageCodec: messageCodec,
+	}
+	if traceEnabledOption, ok := options["traceEnabled"]; ok {
+		if len(traceEnabledOption) == 1 {
+			connection.tracer = spi.NewTracer(connection.connectionId)
+		}
+	}
+	connection.DefaultConnection = _default.NewDefaultConnection(connection,
+		_default.WithPlcFieldHandler(fieldHandler),
+		_default.WithPlcValueHandler(NewValueHandler()),
+	)
+	return connection
+}
+
+func (c *Connection) GetConnectionId() string {
+	return c.connectionId
+}
+
+func (c *Connection) IsTraceEnabled() bool {
+	return c.tracer != nil
+}
+
+func (c *Connection) GetTracer() *spi.Tracer {
+	return c.tracer
+}
+
+func (c *Connection) Connect() <-chan plc4go.PlcConnectionConnectResult {
+	log.Trace().Msg("Connecting")
+	ch := make(chan plc4go.PlcConnectionConnectResult)
+	go func() {
+		connectionConnectResult := <-c.DefaultConnection.Connect()
+		go func() {
+			for c.IsConnected() {
+				log.Debug().Msg("Polling data")
+				incomingMessageChannel := c.messageCodec.GetDefaultIncomingMessageChannel()
+				select {
+				case message := <-incomingMessageChannel:
+					// TODO: implement mapping to subscribers
+					log.Info().Msgf("Received \n%v", message)
+				}
+			}
+			log.Info().Msg("Ending incoming message transfer")
+		}()
+		ch <- connectionConnectResult
+	}()
+	return ch
+}
+
+func (c *Connection) GetConnection() plc4go.PlcConnection {
+	return c
+}
+
+func (c *Connection) GetMessageCodec() spi.MessageCodec {
+	return c.messageCodec
+}
+
+func (c *Connection) SubscriptionRequestBuilder() model.PlcSubscriptionRequestBuilder {
+	return internalModel.NewDefaultPlcSubscriptionRequestBuilder(c.GetPlcFieldHandler(), c.GetPlcValueHandler(), NewSubscriber(c))
+}
+
+func (c *Connection) UnsubscriptionRequestBuilder() model.PlcUnsubscriptionRequestBuilder {
+	panic("Not implemented yet. (at least as a default)")
+}
+
+func (c *Connection) addSubscriber(subscriber *Subscriber) {
+	for _, sub := range c.subscribers {
+		if sub == subscriber {
+			log.Debug().Msgf("Subscriber %v already added", subscriber)
+			return
+		}
+	}
+	c.subscribers = append(c.subscribers, subscriber)
+}
+
+func (c *Connection) String() string {
+	return fmt.Sprintf("bacnetip.Connection")
+}
diff --git a/plc4go/internal/bacnetip/Driver.go b/plc4go/internal/bacnetip/Driver.go
new file mode 100644
index 0000000000..a76192871d
--- /dev/null
+++ b/plc4go/internal/bacnetip/Driver.go
@@ -0,0 +1,77 @@
+/*
+ * 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 bacnetip
+
+import (
+	_default "github.com/apache/plc4x/plc4go/internal/spi/default"
+	"github.com/apache/plc4x/plc4go/internal/spi/transports"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+	"net/url"
+)
+
+type Driver struct {
+	_default.DefaultDriver
+	awaitSetupComplete      bool
+	awaitDisconnectComplete bool
+}
+
+func NewDriver() plc4go.PlcDriver {
+	return &Driver{
+		DefaultDriver:           _default.NewDefaultDriver("bacnet-ip", "BACnet/IP", "udp", NewFieldHandler()),
+		awaitSetupComplete:      true,
+		awaitDisconnectComplete: true,
+	}
+}
+
+func (m *Driver) GetConnection(transportUrl url.URL, transports map[string]transports.Transport, options map[string][]string) <-chan plc4go.PlcConnectionConnectResult {
+	log.Debug().Stringer("transportUrl", &transportUrl).Msgf("Get connection for transport url with %d transport(s) and %d option(s)", len(transports), len(options))
+	// Get an the transport specified in the url
+	transport, ok := transports[transportUrl.Scheme]
+	if !ok {
+		log.Error().Stringer("transportUrl", &transportUrl).Msgf("We couldn't find a transport for scheme %s", transportUrl.Scheme)
+		ch := make(chan plc4go.PlcConnectionConnectResult)
+		go func() {
+			ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.Errorf("couldn't find transport for given transport url %#v", transportUrl))
+		}()
+		return ch
+	}
+	// Provide a default-port to the transport, which is used, if the user doesn't provide on in the connection string.
+	options["defaultUdpPort"] = []string{"47808"}
+	// Have the transport create a new transport-instance.
+	transportInstance, err := transport.CreateTransportInstance(transportUrl, options)
+	if err != nil {
+		log.Error().Stringer("transportUrl", &transportUrl).Msgf("We couldn't create a transport instance for port %#v", options["defaultUdpPort"])
+		ch := make(chan plc4go.PlcConnectionConnectResult)
+		go func() {
+			ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.New("couldn't initialize transport configuration for given transport url "+transportUrl.String()))
+		}()
+		return ch
+	}
+
+	codec := NewMessageCodec(transportInstance)
+	log.Debug().Msgf("working with codec %#v", codec)
+
+	// Create the new connection
+	connection := NewConnection(codec, m.GetPlcFieldHandler(), options)
+	log.Debug().Msg("created connection, connecting now")
+	return connection.Connect()
+}
diff --git a/plc4go/internal/bacnetip/Field.go b/plc4go/internal/bacnetip/Field.go
new file mode 100644
index 0000000000..ba176ece7e
--- /dev/null
+++ b/plc4go/internal/bacnetip/Field.go
@@ -0,0 +1,92 @@
+/*
+ * 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 bacnetip
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"strconv"
+)
+
+type BacNetPlcField interface {
+	GetDeviceIdentifier() uint32
+	GetObjectType() uint16
+	GetObjectInstance() uint32
+}
+
+type PlcField struct {
+	DeviceIdentifier uint32
+	ObjectType       uint16
+	ObjectInstance   uint32
+}
+
+func (m PlcField) GetAddressString() string {
+	return strconv.Itoa(int(m.DeviceIdentifier))
+}
+
+func (m PlcField) GetTypeName() string {
+	return strconv.Itoa(int(m.ObjectType))
+}
+
+func (m PlcField) GetQuantity() uint16 {
+	return 1
+}
+
+func NewField(deviceIdentifier uint32, objectType uint16, objectInstance uint32) PlcField {
+	return PlcField{
+		DeviceIdentifier: deviceIdentifier,
+		ObjectType:       objectType,
+		ObjectInstance:   objectInstance,
+	}
+}
+
+func (m PlcField) GetDeviceIdentifier() uint32 {
+	return m.DeviceIdentifier
+}
+
+func (m PlcField) GetObjectType() uint16 {
+	return m.ObjectType
+}
+
+func (m PlcField) GetObjectInstance() uint32 {
+	return m.ObjectInstance
+}
+
+func (m PlcField) Serialize(writeBuffer utils.WriteBuffer) error {
+	if err := writeBuffer.PushContext("BacNetPlcField"); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.WriteUint32("deviceIdentifier", 32, m.DeviceIdentifier); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.WriteUint16("objectType", 16, m.ObjectType); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.WriteUint32("objectInstance", 32, m.ObjectInstance); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.PopContext("BacNetPlcField"); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/plc4go/internal/bacnetip/FieldHandler.go b/plc4go/internal/bacnetip/FieldHandler.go
new file mode 100644
index 0000000000..0800230b36
--- /dev/null
+++ b/plc4go/internal/bacnetip/FieldHandler.go
@@ -0,0 +1,88 @@
+/*
+ * 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 bacnetip
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+	"github.com/pkg/errors"
+	"regexp"
+	"strconv"
+)
+
+type FieldHandler struct {
+	addressPattern *regexp.Regexp
+}
+
+func NewFieldHandler() FieldHandler {
+	return FieldHandler{
+		addressPattern: regexp.MustCompile(`^(?P<deviceIdentifier>(\d|\*))/(?P<objectType>(\d|\*))/(?P<objectInstance>(\d|\*))`),
+	}
+}
+
+const (
+	DEVICE_IDENTIFIER = "deviceIdentifier"
+	OBJECT_TYPE       = "objectType"
+	OBJECT_INSTANCE   = "objectInstance"
+)
+
+func (m FieldHandler) ParseQuery(query string) (model.PlcField, error) {
+	if match := utils.GetSubgroupMatches(m.addressPattern, query); match != nil {
+		deviceIdentifierString := match[DEVICE_IDENTIFIER]
+		var deviceIdentifier uint32
+		if deviceIdentifierString == "*" {
+			// TODO: find a way to express a wildcard. -1 not an option here
+			deviceIdentifier = 0
+		} else {
+			if parsedDeviceIdentifier, err := strconv.ParseUint(deviceIdentifierString, 10, 32); err != nil {
+				return nil, err
+			} else {
+				deviceIdentifier = uint32(parsedDeviceIdentifier)
+			}
+		}
+		objectTypeString := match[OBJECT_TYPE]
+		var objectType uint16
+		if objectTypeString == "*" {
+			// TODO: find a way to express a wildcard. -1 not an option here
+			deviceIdentifier = 0
+		} else {
+			if parsedObjectType, err := strconv.ParseUint(objectTypeString, 10, 16); err != nil {
+				return nil, err
+			} else {
+				objectType = uint16(parsedObjectType)
+			}
+		}
+		objectInstanceString := match[OBJECT_INSTANCE]
+		var objectInstance uint32
+		if objectInstanceString == "*" {
+			// TODO: find a way to express a wildcard. -1 not an option here
+			objectInstance = 0
+		} else {
+			if parsedObjectInstance, err := strconv.ParseUint(objectInstanceString, 10, 32); err != nil {
+				return nil, err
+			} else {
+				objectInstance = uint32(parsedObjectInstance)
+			}
+		}
+
+		return NewField(deviceIdentifier, objectType, objectInstance), nil
+	}
+	return nil, errors.Errorf("Unable to parse %s", query)
+}
diff --git a/plc4go/internal/bacnetip/MessageCodec.go b/plc4go/internal/bacnetip/MessageCodec.go
new file mode 100644
index 0000000000..efffa6d2f2
--- /dev/null
+++ b/plc4go/internal/bacnetip/MessageCodec.go
@@ -0,0 +1,107 @@
+/*
+ * 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 bacnetip
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	"github.com/apache/plc4x/plc4go/internal/spi/default"
+	"github.com/apache/plc4x/plc4go/internal/spi/transports"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/apache/plc4x/plc4go/protocols/bacnetip/readwrite/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+)
+
+type MessageCodec struct {
+	_default.DefaultCodec
+}
+
+func NewMessageCodec(transportInstance transports.TransportInstance) *MessageCodec {
+	codec := &MessageCodec{}
+	codec.DefaultCodec = _default.NewDefaultCodec(codec, transportInstance, _default.WithCustomMessageHandler(codec.handleCustomMessage))
+	return codec
+}
+
+func (m *MessageCodec) GetCodec() spi.MessageCodec {
+	return m
+}
+
+func (m *MessageCodec) Send(message interface{}) error {
+	log.Trace().Msg("Sending message")
+	// Cast the message to the correct type of struct
+	bvlcPacket := model.CastBVLC(message)
+	// Serialize the request
+	wb := utils.NewWriteBufferByteBased()
+	err := bvlcPacket.Serialize(wb)
+	if err != nil {
+		return errors.Wrap(err, "error serializing request")
+	}
+
+	// Send it to the PLC
+	err = m.GetTransportInstance().Write(wb.GetBytes())
+	if err != nil {
+		return errors.Wrap(err, "error sending request")
+	}
+	return nil
+}
+
+func (m *MessageCodec) Receive() (interface{}, error) {
+	log.Trace().Msg("receiving")
+	// We need at least 6 bytes in order to know how big the packet is in total
+	if num, err := m.GetTransportInstance().GetNumReadableBytes(); (err == nil) && (num >= 4) {
+		log.Debug().Msgf("we got %d readable bytes", num)
+		data, err := m.GetTransportInstance().PeekReadableBytes(4)
+		if err != nil {
+			log.Warn().Err(err).Msg("error peeking")
+			// TODO: Possibly clean up ...
+			return nil, nil
+		}
+		packetSize := uint32((uint16(data[2]) << 8) + uint16(data[3]))
+		if num < packetSize {
+			log.Debug().Msgf("Not enough bytes. Got: %d Need: %d\n", num, packetSize)
+			return nil, nil
+		}
+		data, err = m.GetTransportInstance().Read(packetSize)
+		if err != nil {
+			log.Debug().Err(err).Msg("Error reading")
+			// TODO: Possibly clean up ...
+			return nil, nil
+		}
+		rb := utils.NewReadBufferByteBased(data)
+		bvlcPacket, err := model.BVLCParse(rb)
+		if err != nil {
+			log.Warn().Err(err).Msg("error parsing")
+			// TODO: Possibly clean up ...
+			return nil, nil
+		}
+		return bvlcPacket, nil
+	} else if err != nil {
+		log.Warn().Err(err).Msg("Got error reading")
+		return nil, nil
+	}
+	// TODO: maybe we return here a not enough error error
+	return nil, nil
+}
+
+func (m *MessageCodec) handleCustomMessage(_ *_default.DefaultCodecRequirements, message interface{}) bool {
+	// For now, we just put them in the incoming channel
+	m.GetDefaultIncomingMessageChannel() <- message
+	return true
+}
diff --git a/plc4go/internal/bacnetip/Subscriber.go b/plc4go/internal/bacnetip/Subscriber.go
new file mode 100644
index 0000000000..eac4f8ac12
--- /dev/null
+++ b/plc4go/internal/bacnetip/Subscriber.go
@@ -0,0 +1,71 @@
+/*
+ * 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 bacnetip
+
+import (
+	internalModel "github.com/apache/plc4x/plc4go/internal/spi/model"
+	plc4goModel "github.com/apache/plc4x/plc4go/internal/spi/model"
+	apiModel "github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+)
+
+type Subscriber struct {
+	connection           *Connection
+	subscriptionRequests []internalModel.DefaultPlcSubscriptionRequest
+}
+
+func NewSubscriber(connection *Connection) *Subscriber {
+	return &Subscriber{
+		connection:           connection,
+		subscriptionRequests: []internalModel.DefaultPlcSubscriptionRequest{},
+	}
+}
+
+func (m *Subscriber) Subscribe(subscriptionRequest apiModel.PlcSubscriptionRequest) <-chan apiModel.PlcSubscriptionRequestResult {
+	result := make(chan apiModel.PlcSubscriptionRequestResult)
+	go func() {
+		// Add this subscriber to the connection.
+		m.connection.addSubscriber(m)
+
+		// Save the subscription request
+		m.subscriptionRequests = append(m.subscriptionRequests, subscriptionRequest.(internalModel.DefaultPlcSubscriptionRequest))
+
+		// Just populate all requests with an OK
+		responseCodes := map[string]apiModel.PlcResponseCode{}
+		for _, fieldName := range subscriptionRequest.GetFieldNames() {
+			responseCodes[fieldName] = apiModel.PlcResponseCode_OK
+		}
+
+		result <- &plc4goModel.DefaultPlcSubscriptionRequestResult{
+			Request:  subscriptionRequest,
+			Response: internalModel.NewDefaultPlcSubscriptionResponse(subscriptionRequest, responseCodes),
+			Err:      nil,
+		}
+	}()
+	return result
+}
+
+func (m *Subscriber) Unsubscribe(unsubscriptionRequest apiModel.PlcUnsubscriptionRequest) <-chan apiModel.PlcUnsubscriptionRequestResult {
+	result := make(chan apiModel.PlcUnsubscriptionRequestResult)
+
+	// TODO: As soon as we establish a connection, we start getting data...
+	// subscriptions are more an internal handling of which values to pass where.
+
+	return result
+}
diff --git a/plc4go/internal/bacnetip/ValueHandler.go b/plc4go/internal/bacnetip/ValueHandler.go
new file mode 100644
index 0000000000..ac20e5e0fb
--- /dev/null
+++ b/plc4go/internal/bacnetip/ValueHandler.go
@@ -0,0 +1,32 @@
+/*
+ * 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 bacnetip
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi/values"
+)
+
+type ValueHandler struct {
+	values.IEC61131ValueHandler
+}
+
+func NewValueHandler() ValueHandler {
+	return ValueHandler{}
+}
diff --git a/plc4go/internal/plc4go/eip/Configuration.go b/plc4go/internal/eip/Configuration.go
similarity index 100%
rename from plc4go/internal/plc4go/eip/Configuration.go
rename to plc4go/internal/eip/Configuration.go
diff --git a/plc4go/internal/eip/Connection.go b/plc4go/internal/eip/Connection.go
new file mode 100644
index 0000000000..f2f9e7ad7c
--- /dev/null
+++ b/plc4go/internal/eip/Connection.go
@@ -0,0 +1,208 @@
+/*
+ * 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 eip
+
+import (
+	"fmt"
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	"github.com/apache/plc4x/plc4go/internal/spi/default"
+	internalModel "github.com/apache/plc4x/plc4go/internal/spi/model"
+	"github.com/apache/plc4x/plc4go/internal/spi/plcerrors"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go"
+	apiModel "github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+	readWriteModel "github.com/apache/plc4x/plc4go/protocols/eip/readwrite/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+)
+
+type Connection struct {
+	_default.DefaultConnection
+	messageCodec  spi.MessageCodec
+	configuration Configuration
+	driverContext DriverContext
+	tm            *spi.RequestTransactionManager
+	sessionHandle uint32
+	senderContext []uint8
+	connectionId  string
+	tracer        *spi.Tracer
+}
+
+func NewConnection(messageCodec spi.MessageCodec, configuration Configuration, driverContext DriverContext, fieldHandler spi.PlcFieldHandler, tm *spi.RequestTransactionManager, options map[string][]string) *Connection {
+	connection := &Connection{
+		messageCodec:  messageCodec,
+		configuration: configuration,
+		driverContext: driverContext,
+		tm:            tm,
+	}
+	if traceEnabledOption, ok := options["traceEnabled"]; ok {
+		if len(traceEnabledOption) == 1 {
+			connection.tracer = spi.NewTracer(connection.connectionId)
+		}
+	}
+	connection.DefaultConnection = _default.NewDefaultConnection(connection,
+		_default.WithPlcFieldHandler(fieldHandler),
+		_default.WithPlcValueHandler(NewValueHandler()),
+	)
+	return connection
+}
+
+func (m *Connection) GetConnectionId() string {
+	return m.connectionId
+}
+
+func (m *Connection) IsTraceEnabled() bool {
+	return m.tracer != nil
+}
+
+func (m *Connection) GetTracer() *spi.Tracer {
+	return m.tracer
+}
+
+func (m *Connection) GetConnection() plc4go.PlcConnection {
+	return m
+}
+
+func (m *Connection) GetMessageCodec() spi.MessageCodec {
+	return m.messageCodec
+}
+
+func (m *Connection) Connect() <-chan plc4go.PlcConnectionConnectResult {
+	log.Trace().Msg("Connecting")
+	ch := make(chan plc4go.PlcConnectionConnectResult)
+	go func() {
+		err := m.messageCodec.Connect()
+		if err != nil {
+			ch <- _default.NewDefaultPlcConnectionConnectResult(m, err)
+		}
+
+		// For testing purposes we can skip the waiting for a complete connection
+		if !m.driverContext.awaitSetupComplete {
+			go m.setupConnection(ch)
+			log.Warn().Msg("Connection used in an unsafe way. !!!DON'T USE IN PRODUCTION!!!")
+			// Here we write directly and don't wait till the connection is "really" connected
+			// Note: we can't use fireConnected here as it's guarded against m.driverContext.awaitSetupComplete
+			ch <- _default.NewDefaultPlcConnectionConnectResult(m, err)
+			m.SetConnected(true)
+			return
+		}
+
+		m.setupConnection(ch)
+	}()
+	return ch
+}
+
+func (m *Connection) Close() <-chan plc4go.PlcConnectionCloseResult {
+	result := make(chan plc4go.PlcConnectionCloseResult)
+	go func() {
+		log.Debug().Msg("Sending UnregisterSession EIP Packet")
+		_ = m.messageCodec.SendRequest(
+			readWriteModel.NewEipDisconnectRequest(m.sessionHandle, 0, make([]byte, 8), 0),
+			func(message interface{}) bool {
+				return true
+			},
+			func(message interface{}) error {
+				return nil
+			},
+			func(err error) error {
+				return nil
+			},
+			m.GetTtl(),
+		) //Unregister gets no response
+		log.Debug().Msgf("Unregistred Session %d", m.sessionHandle)
+	}()
+	return result
+}
+
+func (m *Connection) setupConnection(ch chan plc4go.PlcConnectionConnectResult) {
+	log.Debug().Msg("Sending EIP Connection Request")
+	if err := m.messageCodec.SendRequest(
+		readWriteModel.NewEipConnectionRequest(0, 0, make([]byte, 8), 0),
+		func(message interface{}) bool {
+			eipPacket := readWriteModel.CastEipPacket(message)
+			if eipPacket == nil {
+				return false
+			}
+			eipPacketConnectionRequest := readWriteModel.CastEipConnectionRequest(eipPacket.Child)
+			return eipPacketConnectionRequest != nil
+		},
+		func(message interface{}) error {
+			eipPacket := readWriteModel.CastEipPacket(message)
+			if eipPacket.Status == 0 {
+				m.sessionHandle = eipPacket.SessionHandle
+				m.senderContext = eipPacket.SenderContext
+				log.Debug().Msgf("Got assigned with Session %d", m.sessionHandle)
+				// Send an event that connection setup is complete.
+				m.fireConnected(ch)
+			} else {
+
+			}
+			return nil
+		},
+		func(err error) error {
+			// If this is a timeout, do a check if the connection requires a reconnection
+			if _, isTimeout := err.(plcerrors.TimeoutError); isTimeout {
+				log.Warn().Msg("Timeout during Connection establishing, closing channel...")
+				m.Close()
+			}
+			m.fireConnectionError(errors.Wrap(err, "got error processing request"), ch)
+			return nil
+		},
+		m.GetTtl(),
+	); err != nil {
+		m.fireConnectionError(errors.Wrap(err, "Error during sending of EIP Connection Request"), ch)
+	}
+}
+
+func (m *Connection) fireConnectionError(err error, ch chan<- plc4go.PlcConnectionConnectResult) {
+	if m.driverContext.awaitSetupComplete {
+		ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.Wrap(err, "Error during connection"))
+	} else {
+		log.Error().Err(err).Msg("awaitSetupComplete set to false and we got a error during connect")
+	}
+}
+
+func (m *Connection) fireConnected(ch chan<- plc4go.PlcConnectionConnectResult) {
+	if m.driverContext.awaitSetupComplete {
+		ch <- _default.NewDefaultPlcConnectionConnectResult(m, nil)
+	} else {
+		log.Info().Msg("Successfully connected")
+	}
+	m.SetConnected(true)
+}
+
+func (m *Connection) GetMetadata() apiModel.PlcConnectionMetadata {
+	return _default.DefaultConnectionMetadata{
+		ProvidesReading: true,
+		ProvidesWriting: true,
+	}
+}
+
+func (m *Connection) ReadRequestBuilder() apiModel.PlcReadRequestBuilder {
+	return internalModel.NewDefaultPlcReadRequestBuilder(m.GetPlcFieldHandler(), NewReader(m.messageCodec, m.tm, m.configuration, &m.sessionHandle))
+}
+
+func (m *Connection) WriteRequestBuilder() apiModel.PlcWriteRequestBuilder {
+	return internalModel.NewDefaultPlcWriteRequestBuilder(
+		m.GetPlcFieldHandler(), m.GetPlcValueHandler(), NewWriter(m.messageCodec, m.tm, m.configuration, &m.sessionHandle, &m.senderContext))
+}
+
+func (m *Connection) String() string {
+	return fmt.Sprintf("eip.Connection")
+}
diff --git a/plc4go/internal/eip/Driver.go b/plc4go/internal/eip/Driver.go
new file mode 100644
index 0000000000..880c66b3f9
--- /dev/null
+++ b/plc4go/internal/eip/Driver.go
@@ -0,0 +1,110 @@
+/*
+ * 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 eip
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	_default "github.com/apache/plc4x/plc4go/internal/spi/default"
+	"github.com/apache/plc4x/plc4go/internal/spi/transports"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+	"net/url"
+)
+
+type Driver struct {
+	_default.DefaultDriver
+	tm                      spi.RequestTransactionManager
+	awaitSetupComplete      bool
+	awaitDisconnectComplete bool
+}
+
+func NewDriver() plc4go.PlcDriver {
+	return &Driver{
+		DefaultDriver:           _default.NewDefaultDriver("eip", "EthernetIP", "tcp", NewFieldHandler()),
+		tm:                      spi.NewRequestTransactionManager(1),
+		awaitSetupComplete:      true,
+		awaitDisconnectComplete: true,
+	}
+}
+
+func (m *Driver) GetConnection(transportUrl url.URL, transports map[string]transports.Transport, options map[string][]string) <-chan plc4go.PlcConnectionConnectResult {
+	log.Debug().Stringer("transportUrl", &transportUrl).Msgf("Get connection for transport url with %d transport(s) and %d option(s)", len(transports), len(options))
+	// Get an the transport specified in the url
+	transport, ok := transports[transportUrl.Scheme]
+	if !ok {
+		log.Error().Stringer("transportUrl", &transportUrl).Msgf("We couldn't find a transport for scheme %s", transportUrl.Scheme)
+		ch := make(chan plc4go.PlcConnectionConnectResult)
+		go func() {
+			ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.Errorf("couldn't find transport for given transport url %#v", transportUrl))
+		}()
+		return ch
+	}
+	// Provide a default-port to the transport, which is used, if the user doesn't provide on in the connection string.
+	options["defaultTcpPort"] = []string{"44818"}
+	// Have the transport create a new transport-instance.
+	transportInstance, err := transport.CreateTransportInstance(transportUrl, options)
+	if err != nil {
+		log.Error().Stringer("transportUrl", &transportUrl).Msgf("We couldn't create a transport instance for port %#v", options["defaultTcpPort"])
+		ch := make(chan plc4go.PlcConnectionConnectResult)
+		go func() {
+			ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.New("couldn't initialize transport configuration for given transport url "+transportUrl.String()))
+		}()
+		return ch
+	}
+
+	codec := NewMessageCodec(transportInstance)
+	log.Debug().Msgf("working with codec %#v", codec)
+
+	configuration, err := ParseFromOptions(options)
+	if err != nil {
+		log.Error().Err(err).Msgf("Invalid options")
+		ch := make(chan plc4go.PlcConnectionConnectResult)
+		go func() {
+			ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.Wrap(err, "Invalid options"))
+		}()
+		return ch
+	}
+
+	driverContext, err := NewDriverContext(configuration)
+	if err != nil {
+		log.Error().Err(err).Msgf("Invalid options")
+		ch := make(chan plc4go.PlcConnectionConnectResult)
+		go func() {
+			ch <- _default.NewDefaultPlcConnectionConnectResult(nil, errors.Wrap(err, "Invalid options"))
+		}()
+		return ch
+	}
+	driverContext.awaitSetupComplete = m.awaitSetupComplete
+	driverContext.awaitDisconnectComplete = m.awaitDisconnectComplete
+
+	// Create the new connection
+	connection := NewConnection(codec, configuration, driverContext, m.GetPlcFieldHandler(), &m.tm, options)
+	log.Debug().Msg("created connection, connecting now")
+	return connection.Connect()
+}
+
+func (m *Driver) SetAwaitSetupComplete(awaitComplete bool) {
+	m.awaitSetupComplete = awaitComplete
+}
+
+func (m *Driver) SetAwaitDisconnectComplete(awaitComplete bool) {
+	m.awaitDisconnectComplete = awaitComplete
+}
diff --git a/plc4go/internal/plc4go/eip/DriverContext.go b/plc4go/internal/eip/DriverContext.go
similarity index 100%
rename from plc4go/internal/plc4go/eip/DriverContext.go
rename to plc4go/internal/eip/DriverContext.go
diff --git a/plc4go/internal/eip/Field.go b/plc4go/internal/eip/Field.go
new file mode 100644
index 0000000000..76bb83da18
--- /dev/null
+++ b/plc4go/internal/eip/Field.go
@@ -0,0 +1,99 @@
+/*
+ * 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 eip
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	readWrite "github.com/apache/plc4x/plc4go/protocols/eip/readwrite/model"
+)
+
+type EIPPlcField interface {
+	GetTag() string
+	GetType() readWrite.CIPDataTypeCode
+	GetElementNb() uint16
+}
+
+type PlcField struct {
+	Tag       string
+	Type      readWrite.CIPDataTypeCode
+	ElementNb uint16
+}
+
+func (m PlcField) GetAddressString() string {
+	return m.GetTag()
+}
+
+func (m PlcField) GetTypeName() string {
+	return m.GetType().String()
+}
+
+func (m PlcField) GetQuantity() uint16 {
+	return 1
+}
+
+func NewField(tag string, _type readWrite.CIPDataTypeCode, elementNb uint16) PlcField {
+	return PlcField{
+		Tag:       tag,
+		Type:      _type,
+		ElementNb: elementNb,
+	}
+}
+
+func (m PlcField) GetTag() string {
+	return m.Tag
+}
+
+func (m PlcField) GetType() readWrite.CIPDataTypeCode {
+	return m.Type
+}
+
+func (m PlcField) GetElementNb() uint16 {
+	return m.ElementNb
+}
+
+func (m PlcField) Serialize(writeBuffer utils.WriteBuffer) error {
+	if err := writeBuffer.PushContext("EipField"); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.WriteString("node", uint32(len([]rune(m.Tag))*8), "UTF-8", m.Tag); err != nil {
+		return err
+	}
+
+	if m.Type != 0 {
+		if err := writeBuffer.WriteString("type", uint32(len([]rune(m.Type.String()))*8), "UTF-8", m.Type.String()); err != nil {
+			return err
+		}
+	}
+
+	if err := writeBuffer.WriteUint16("elementNb", 16, m.ElementNb); err != nil {
+		return err
+	}
+
+	// TODO: remove this from the spec
+	if err := writeBuffer.WriteString("defaultJavaType", uint32(len([]rune("java.lang.Object"))*8), "UTF-8", "java.lang.Object"); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.PopContext("EipField"); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/plc4go/internal/eip/FieldHandler.go b/plc4go/internal/eip/FieldHandler.go
new file mode 100644
index 0000000000..a31ea4af40
--- /dev/null
+++ b/plc4go/internal/eip/FieldHandler.go
@@ -0,0 +1,56 @@
+/*
+ * 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 eip
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+	readWriteModel "github.com/apache/plc4x/plc4go/protocols/eip/readwrite/model"
+	"github.com/pkg/errors"
+	"regexp"
+	"strconv"
+)
+
+type FieldHandler struct {
+	addressPattern *regexp.Regexp
+}
+
+func NewFieldHandler() FieldHandler {
+	return FieldHandler{
+		addressPattern: regexp.MustCompile(`^%(?P<tag>[a-zA-Z_.0-9]+\[?[0-9]*]?):?(?P<dataType>[A-Z]*):?(?P<elementNb>[0-9]*)`),
+	}
+}
+
+const (
+	TAG        = "tag"
+	DATA_TYPE  = "dataType"
+	ELEMENT_NB = "elementNb"
+)
+
+func (m FieldHandler) ParseQuery(query string) (model.PlcField, error) {
+	if match := utils.GetSubgroupMatches(m.addressPattern, query); match != nil {
+		tag := match[TAG]
+		_type := readWriteModel.CIPDataTypeCodeByName(match[DATA_TYPE])
+		parsedUint, _ := strconv.ParseUint(match[ELEMENT_NB], 10, 16)
+		elementNb := uint16(parsedUint)
+		return NewField(tag, _type, elementNb), nil
+	}
+	return nil, errors.Errorf("Unable to parse %s", query)
+}
diff --git a/plc4go/internal/eip/MessageCodec.go b/plc4go/internal/eip/MessageCodec.go
new file mode 100644
index 0000000000..2684d331bb
--- /dev/null
+++ b/plc4go/internal/eip/MessageCodec.go
@@ -0,0 +1,102 @@
+/*
+ * 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 eip
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	"github.com/apache/plc4x/plc4go/internal/spi/default"
+	"github.com/apache/plc4x/plc4go/internal/spi/transports"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/apache/plc4x/plc4go/protocols/eip/readwrite/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+)
+
+type MessageCodec struct {
+	_default.DefaultCodec
+}
+
+func NewMessageCodec(transportInstance transports.TransportInstance) *MessageCodec {
+	codec := &MessageCodec{}
+	codec.DefaultCodec = _default.NewDefaultCodec(codec, transportInstance)
+	return codec
+}
+
+func (m *MessageCodec) GetCodec() spi.MessageCodec {
+	return m
+}
+
+func (m *MessageCodec) Send(message interface{}) error {
+	log.Trace().Msg("Sending message")
+	// Cast the message to the correct type of struct
+	eipPacket := model.CastEipPacket(message)
+	// Serialize the request
+	wb := utils.NewLittleEndianWriteBufferByteBased()
+	err := eipPacket.Serialize(wb)
+	if err != nil {
+		return errors.Wrap(err, "error serializing request")
+	}
+
+	// Send it to the PLC
+	err = m.GetTransportInstance().Write(wb.GetBytes())
+	if err != nil {
+		return errors.Wrap(err, "error sending request")
+	}
+	return nil
+}
+
+func (m *MessageCodec) Receive() (interface{}, error) {
+	log.Trace().Msg("receiving")
+	// We need at least 6 bytes in order to know how big the packet is in total
+	if num, err := m.GetTransportInstance().GetNumReadableBytes(); (err == nil) && (num >= 4) {
+		log.Debug().Msgf("we got %d readable bytes", num)
+		data, err := m.GetTransportInstance().PeekReadableBytes(4)
+		if err != nil {
+			log.Warn().Err(err).Msg("error peeking")
+			// TODO: Possibly clean up ...
+			return nil, nil
+		}
+		//Second byte for the size and then add the header size 24
+		packetSize := uint32(((uint16(data[3]) << 8) + uint16(data[2])) + 24)
+		if num < packetSize {
+			log.Debug().Msgf("Not enough bytes. Got: %d Need: %d\n", num, packetSize)
+			return nil, nil
+		}
+		data, err = m.GetTransportInstance().Read(packetSize)
+		if err != nil {
+			log.Debug().Err(err).Msg("Error reading")
+			// TODO: Possibly clean up ...
+			return nil, nil
+		}
+		rb := utils.NewLittleEndianReadBufferByteBased(data)
+		eipPacket, err := model.EipPacketParse(rb)
+		if err != nil {
+			log.Warn().Err(err).Msg("error parsing")
+			// TODO: Possibly clean up ...
+			return nil, nil
+		}
+		return eipPacket, nil
+	} else if err != nil {
+		log.Warn().Err(err).Msg("Got error reading")
+		return nil, nil
+	}
+	// TODO: maybe we return here a not enough error error
+	return nil, nil
+}
diff --git a/plc4go/internal/eip/Reader.go b/plc4go/internal/eip/Reader.go
new file mode 100644
index 0000000000..7606a591c2
--- /dev/null
+++ b/plc4go/internal/eip/Reader.go
@@ -0,0 +1,541 @@
+/*
+ * 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 eip
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	plc4goModel "github.com/apache/plc4x/plc4go/internal/spi/model"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	spiValues "github.com/apache/plc4x/plc4go/internal/spi/values"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go/values"
+	readWriteModel "github.com/apache/plc4x/plc4go/protocols/eip/readwrite/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type Reader struct {
+	messageCodec  spi.MessageCodec
+	tm            *spi.RequestTransactionManager
+	configuration Configuration
+	sessionHandle *uint32
+}
+
+func NewReader(messageCodec spi.MessageCodec, tm *spi.RequestTransactionManager, configuration Configuration, sessionHandle *uint32) *Reader {
+	return &Reader{
+		messageCodec:  messageCodec,
+		tm:            tm,
+		configuration: configuration,
+		sessionHandle: sessionHandle,
+	}
+}
+
+func (m *Reader) Read(readRequest model.PlcReadRequest) <-chan model.PlcReadRequestResult {
+	log.Trace().Msg("Reading")
+	result := make(chan model.PlcReadRequestResult)
+	go func() {
+
+		requestItems := make([]*readWriteModel.CipService, len(readRequest.GetFieldNames()))
+		for i, fieldName := range readRequest.GetFieldNames() {
+			plcField := readRequest.GetField(fieldName).(EIPPlcField)
+			tag := plcField.GetTag()
+			elements := uint16(1)
+			if plcField.GetElementNb() > 1 {
+				elements = plcField.GetElementNb()
+			}
+			ansi, err := toAnsi(tag)
+			if err != nil {
+				result <- &plc4goModel.DefaultPlcReadRequestResult{
+					Request:  readRequest,
+					Response: nil,
+					Err:      errors.Wrapf(err, "Error encoding eip ansi for field %s", fieldName),
+				}
+				return
+			}
+			request := readWriteModel.NewCipReadRequest(getRequestSize(tag), ansi, elements, 0).GetParent()
+			requestItems[i] = request
+		}
+		if len(requestItems) > 1 {
+			nb := uint16(len(requestItems))
+			offsets := make([]uint16, nb)
+			offset := 2 + nb*2
+			for i := uint16(0); i < nb; i++ {
+				offsets[i] = offset
+				offset += requestItems[i].GetLengthInBytes()
+			}
+
+			serviceArr := make([]*readWriteModel.CipService, nb)
+			for i := uint16(0); i < nb; i++ {
+				serviceArr[i] = requestItems[i]
+			}
+
+			data := readWriteModel.NewServices(nb, offsets, serviceArr, 0)
+			//Encapsulate the data
+			pkt := readWriteModel.NewCipRRData(
+				readWriteModel.NewCipExchange(
+					readWriteModel.NewCipUnconnectedRequest(
+						readWriteModel.NewMultipleServiceRequest(data, 0).GetParent(),
+						m.configuration.backplane,
+						m.configuration.slot,
+						0,
+					).GetParent(),
+					0,
+				),
+				*m.sessionHandle,
+				0,
+				make([]byte, 8),
+				0,
+				0,
+			)
+
+			// Start a new request-transaction (Is ended in the response-handler)
+			transaction := m.tm.StartTransaction()
+			transaction.Submit(func() {
+				// Send the  over the wire
+				log.Trace().Msg("Send ")
+				if err := m.messageCodec.SendRequest(
+					pkt,
+					func(message interface{}) bool {
+						eipPacket := readWriteModel.CastEipPacket(message)
+						if eipPacket == nil {
+							return false
+						}
+						cipRRData := readWriteModel.CastCipRRData(eipPacket.Child)
+						if cipRRData == nil {
+							return false
+						}
+						if eipPacket.SessionHandle != *m.sessionHandle {
+							return false
+						}
+						multipleServiceResponse := readWriteModel.CastMultipleServiceResponse(cipRRData.Exchange.Service)
+						if multipleServiceResponse == nil {
+							return false
+						}
+						if multipleServiceResponse.ServiceNb != nb {
+							return false
+						}
+						return true
+					},
+					func(message interface{}) error {
+						// Convert the response into an
+						log.Trace().Msg("convert response to ")
+						eipPacket := readWriteModel.CastEipPacket(message)
+						cipRRData := readWriteModel.CastCipRRData(eipPacket.Child)
+						multipleServiceResponse := readWriteModel.CastMultipleServiceResponse(cipRRData.Exchange.Service)
+						// Convert the eip response into a PLC4X response
+						log.Trace().Msg("convert response to PLC4X response")
+						readResponse, err := m.ToPlc4xReadResponse(multipleServiceResponse.CipService, readRequest)
+
+						if err != nil {
+							result <- &plc4goModel.DefaultPlcReadRequestResult{
+								Request: readRequest,
+								Err:     errors.Wrap(err, "Error decoding response"),
+							}
+							return transaction.EndRequest()
+						}
+						result <- &plc4goModel.DefaultPlcReadRequestResult{
+							Request:  readRequest,
+							Response: readResponse,
+						}
+						return transaction.EndRequest()
+					},
+					func(err error) error {
+						result <- &plc4goModel.DefaultPlcReadRequestResult{
+							Request: readRequest,
+							Err:     errors.Wrap(err, "got timeout while waiting for response"),
+						}
+						return transaction.EndRequest()
+					},
+					time.Second*1); err != nil {
+					result <- &plc4goModel.DefaultPlcReadRequestResult{
+						Request:  readRequest,
+						Response: nil,
+						Err:      errors.Wrap(err, "error sending message"),
+					}
+					_ = transaction.EndRequest()
+				}
+			})
+		} else if len(requestItems) == 1 {
+			//Encapsulate the data
+			pkt := readWriteModel.NewCipRRData(
+				readWriteModel.NewCipExchange(
+					readWriteModel.NewCipUnconnectedRequest(
+						requestItems[0],
+						m.configuration.backplane,
+						m.configuration.slot,
+						0,
+					).GetParent(),
+					0,
+				),
+				*m.sessionHandle,
+				0,
+				make([]byte, 8),
+				0,
+				0,
+			)
+
+			// Start a new request-transaction (Is ended in the response-handler)
+			transaction := m.tm.StartTransaction()
+			transaction.Submit(func() {
+				// Send the  over the wire
+				log.Trace().Msg("Send ")
+				if err := m.messageCodec.SendRequest(
+					pkt,
+					func(message interface{}) bool {
+						eipPacket := readWriteModel.CastEipPacket(message)
+						if eipPacket == nil {
+							return false
+						}
+						cipRRData := readWriteModel.CastCipRRData(eipPacket.Child)
+						if cipRRData == nil {
+							return false
+						}
+						if eipPacket.SessionHandle != *m.sessionHandle {
+							return false
+						}
+						cipReadResponse := readWriteModel.CastCipReadResponse(cipRRData.Exchange.Service)
+						if cipReadResponse == nil {
+							return false
+						}
+						return true
+					},
+					func(message interface{}) error {
+						// Convert the response into an
+						log.Trace().Msg("convert response to ")
+						eipPacket := readWriteModel.CastEipPacket(message)
+						cipRRData := readWriteModel.CastCipRRData(eipPacket.Child)
+						cipReadResponse := readWriteModel.CastCipReadResponse(cipRRData.Exchange.Service)
+						// Convert the eip response into a PLC4X response
+						log.Trace().Msg("convert response to PLC4X response")
+						readResponse, err := m.ToPlc4xReadResponse(cipReadResponse.CipService, readRequest)
+
+						if err != nil {
+							result <- &plc4goModel.DefaultPlcReadRequestResult{
+								Request: readRequest,
+								Err:     errors.Wrap(err, "Error decoding response"),
+							}
+							return transaction.EndRequest()
+						}
+						result <- &plc4goModel.DefaultPlcReadRequestResult{
+							Request:  readRequest,
+							Response: readResponse,
+						}
+						return transaction.EndRequest()
+					},
+					func(err error) error {
+						result <- &plc4goModel.DefaultPlcReadRequestResult{
+							Request: readRequest,
+							Err:     errors.Wrap(err, "got timeout while waiting for response"),
+						}
+						return transaction.EndRequest()
+					},
+					time.Second*1); err != nil {
+					result <- &plc4goModel.DefaultPlcReadRequestResult{
+						Request:  readRequest,
+						Response: nil,
+						Err:      errors.Wrap(err, "error sending message"),
+					}
+					_ = transaction.EndRequest()
+				}
+			})
+		}
+	}()
+	return result
+}
+
+func getRequestSize(tag string) int8 {
+	//We need the size of the request in words (0x91, tagLength, ... tag + possible pad)
+	// Taking half to get word size
+	isArray := false
+	isStruct := false
+	tagIsolated := tag
+
+	if strings.Contains(tag, "[") {
+		isArray = true
+		tagIsolated = tag[0:strings.Index(tag, "[")]
+	}
+
+	if strings.Contains(tag, ".") {
+		isStruct = true
+		tagIsolated = strings.Replace(tagIsolated, ".", "", -1)
+	}
+	dataLength := (len(tagIsolated) + 2) + (len(tagIsolated) % 2)
+	if isArray {
+		dataLength += 2
+	}
+	if isStruct {
+		dataLength += 2
+	}
+	requestPathSize := (int8)(dataLength / 2)
+	return requestPathSize
+}
+
+func toAnsi(tag string) ([]byte, error) {
+	arrayIndex := byte(0)
+	isArray := false
+	isStruct := false
+	tagFinal := tag
+	if strings.Contains(tag, "[") {
+		isArray = true
+		index := tag[strings.Index(tag, "[")+1 : strings.Index(tag, "]")]
+		parsedArrayIndex, err := strconv.ParseUint(index, 10, 8)
+		if err != nil {
+			return nil, err
+		}
+		arrayIndex = byte(parsedArrayIndex)
+		tagFinal = tag[0:strings.Index(tag, "[")]
+	}
+	if strings.Contains(tag, ".") {
+		tagFinal = tag[0:strings.Index(tag, ".")]
+		isStruct = true
+	}
+	isPadded := len(tagFinal)%2 != 0
+	dataSegLength := 2 + len(tagFinal)
+	if isPadded {
+		dataSegLength += 1
+	}
+	if isArray {
+		dataSegLength += 2
+	}
+
+	if isStruct {
+		for _, subStr := range strings.Split(tag[strings.Index(tag, ".")+1:], ".") {
+			dataSegLength += 2 + len(subStr) + len(subStr)%2
+		}
+	}
+
+	buffer := utils.NewLittleEndianWriteBufferByteBased()
+
+	err := buffer.WriteByte("", 0x91)
+	if err != nil {
+		return nil, err
+	}
+	err = buffer.WriteByte("", byte(len(tagFinal)))
+	if err != nil {
+		return nil, err
+	}
+
+	quoteToASCII := strconv.QuoteToASCII(tagFinal)
+	err = buffer.WriteByteArray("", []byte(quoteToASCII)[1:len(quoteToASCII)-1])
+	if err != nil {
+		return nil, err
+	}
+
+	if isPadded {
+		err = buffer.WriteByte("", 0x00)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	if isArray {
+		err = buffer.WriteByte("", 0x28)
+		if err != nil {
+			return nil, err
+		}
+		err = buffer.WriteByte("", arrayIndex)
+		if err != nil {
+			return nil, err
+		}
+	}
+	if isStruct {
+		ansi, err := toAnsi(tag[strings.Index(tag, ".")+1:])
+		if err != nil {
+			return nil, err
+		}
+		err = buffer.WriteByteArray("", ansi)
+		if err != nil {
+			return nil, err
+		}
+	}
+	return buffer.GetBytes(), nil
+}
+
+func (m *Reader) ToPlc4xReadResponse(response *readWriteModel.CipService, readRequest model.PlcReadRequest) (model.PlcReadResponse, error) {
+	plcValues := map[string]values.PlcValue{}
+	responseCodes := map[string]model.PlcResponseCode{}
+	switch response.Child.(type) {
+	case *readWriteModel.CipReadResponse: // only 1 field
+		cipReadResponse := response.Child.(*readWriteModel.CipReadResponse)
+		fieldName := readRequest.GetFieldNames()[0]
+		field := readRequest.GetField(fieldName).(EIPPlcField)
+		code := decodeResponseCode(cipReadResponse.Status)
+		var plcValue values.PlcValue
+		_type := cipReadResponse.DataType
+		data := utils.NewLittleEndianReadBufferByteBased(cipReadResponse.Data)
+		if code == model.PlcResponseCode_OK {
+			var err error
+			plcValue, err = parsePlcValue(field, data, _type)
+			if err != nil {
+				return nil, err
+			}
+		}
+		plcValues[fieldName] = plcValue
+		responseCodes[fieldName] = code
+	case *readWriteModel.MultipleServiceResponse: //Multiple response
+		multipleServiceResponse := response.Child.(*readWriteModel.MultipleServiceResponse)
+		nb := multipleServiceResponse.ServiceNb
+		arr := make([]*readWriteModel.CipService, nb)
+		read := utils.NewLittleEndianReadBufferByteBased(multipleServiceResponse.ServicesData)
+		total := read.GetTotalBytes()
+		for i := uint16(0); i < nb; i++ {
+			length := uint16(0)
+			offset := multipleServiceResponse.Offsets[i] - multipleServiceResponse.Offsets[0] //Substract first offset as we only have the service in the buffer (not servicesNb and offsets)
+			if i == nb-1 {
+				length = uint16(total) - offset //Get the rest if last
+			} else {
+				length = multipleServiceResponse.Offsets[i+1] - offset - multipleServiceResponse.Offsets[0] //Calculate length with offsets (substracting first offset)
+			}
+			serviceBuf := utils.NewLittleEndianReadBufferByteBased(read.GetBytes()[offset : offset+length])
+			var err error
+			arr[i], err = readWriteModel.CipServiceParse(serviceBuf, length)
+			if err != nil {
+				return nil, err
+			}
+		}
+		services := readWriteModel.NewServices(nb, multipleServiceResponse.Offsets, arr, 0)
+		for i, fieldName := range readRequest.GetFieldNames() {
+			field := readRequest.GetField(fieldName).(EIPPlcField)
+			if cipReadResponse, ok := services.Services[i].Child.(*readWriteModel.CipReadResponse); ok {
+				code := decodeResponseCode(cipReadResponse.Status)
+				_type := cipReadResponse.DataType
+				data := utils.NewLittleEndianReadBufferByteBased(cipReadResponse.Data)
+				var plcValue values.PlcValue
+				if code == model.PlcResponseCode_OK {
+					var err error
+					plcValue, err = parsePlcValue(field, data, _type)
+					if err != nil {
+						return nil, err
+					}
+				}
+
+				plcValues[fieldName] = plcValue
+				responseCodes[fieldName] = code
+			} else {
+				responseCodes[fieldName] = model.PlcResponseCode_INTERNAL_ERROR
+			}
+		}
+	default:
+		return nil, errors.Errorf("unsupported response type %T", response.Child)
+	}
+
+	// Return the response
+	log.Trace().Msg("Returning the response")
+	return plc4goModel.NewDefaultPlcReadResponse(readRequest, responseCodes, plcValues), nil
+}
+
+func parsePlcValue(field EIPPlcField, data utils.ReadBufferByteBased, _type readWriteModel.CIPDataTypeCode) (values.PlcValue, error) {
+	nb := field.GetElementNb()
+	if nb > 1 {
+		list := make([]values.PlcValue, 0)
+		for i := uint16(0); i < nb; i++ {
+			switch _type {
+			case readWriteModel.CIPDataTypeCode_DINT:
+				readInt32, err := data.ReadInt32("", _type.Size()*8)
+				if err != nil {
+					return nil, err
+				}
+				list = append(list, spiValues.NewPlcDINT(readInt32))
+			case readWriteModel.CIPDataTypeCode_INT:
+				readInt16, err := data.ReadInt16("", _type.Size()*8)
+				if err != nil {
+					return nil, err
+				}
+				list = append(list, spiValues.NewPlcINT(readInt16))
+			case readWriteModel.CIPDataTypeCode_SINT:
+				readInt8, err := data.ReadInt8("", _type.Size()*8)
+				if err != nil {
+					return nil, err
+				}
+				list = append(list, spiValues.NewPlcSINT(readInt8))
+			case readWriteModel.CIPDataTypeCode_REAL:
+				if _type.Size()*8 != 64 {
+					panic("Unexpected size")
+				}
+				readFloat64, err := data.ReadFloat64("", 64)
+				if err != nil {
+					return nil, err
+				}
+				list = append(list, spiValues.NewPlcLREAL(readFloat64))
+			case readWriteModel.CIPDataTypeCode_BOOL:
+				bit, err := data.ReadBit("")
+				if err != nil {
+					return nil, err
+				}
+				list = append(list, spiValues.NewPlcBOOL(bit))
+			default:
+				return nil, errors.Errorf("Unknown type %v", _type)
+			}
+		}
+		return spiValues.NewPlcList(list), nil
+	} else {
+		switch _type {
+		case readWriteModel.CIPDataTypeCode_SINT:
+			readByte, err := data.ReadInt8("", _type.Size()*8)
+			if err != nil {
+				return nil, err
+			}
+			return spiValues.NewPlcSINT(readByte), nil
+		case readWriteModel.CIPDataTypeCode_INT:
+			readInt16, err := data.ReadInt16("", _type.Size()*8)
+			if err != nil {
+				return nil, err
+			}
+			return spiValues.NewPlcINT(readInt16), nil
+		case readWriteModel.CIPDataTypeCode_DINT:
+			readInt32, err := data.ReadInt32("", _type.Size()*8)
+			if err != nil {
+				return nil, err
+			}
+			return spiValues.NewPlcDINT(readInt32), nil
+		case readWriteModel.CIPDataTypeCode_REAL:
+			if _type.Size()*8 != 64 {
+				panic("Unexpected size")
+			}
+			readFloat32, err := data.ReadFloat32("", 64)
+			if err != nil {
+				return nil, err
+			}
+			return spiValues.NewPlcREAL(readFloat32), nil
+		case readWriteModel.CIPDataTypeCode_BOOL:
+			readBit, err := data.ReadBit("")
+			if err != nil {
+				return nil, err
+			}
+			return spiValues.NewPlcBOOL(readBit), nil
+		default:
+			return nil, errors.Errorf("Unknown type %v", _type)
+		}
+	}
+}
+
+// Helper to convert the return codes returned from the eip into one of our standard
+func decodeResponseCode(status uint8) model.PlcResponseCode {
+	//TODO other status
+	switch status {
+	case 0:
+		return model.PlcResponseCode_OK
+	default:
+		return model.PlcResponseCode_INTERNAL_ERROR
+	}
+}
diff --git a/plc4go/internal/eip/ValueHandler.go b/plc4go/internal/eip/ValueHandler.go
new file mode 100644
index 0000000000..541fdbb671
--- /dev/null
+++ b/plc4go/internal/eip/ValueHandler.go
@@ -0,0 +1,32 @@
+/*
+ * 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 eip
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi/values"
+)
+
+type ValueHandler struct {
+	values.IEC61131ValueHandler
+}
+
+func NewValueHandler() ValueHandler {
+	return ValueHandler{}
+}
diff --git a/plc4go/internal/eip/Writer.go b/plc4go/internal/eip/Writer.go
new file mode 100644
index 0000000000..a1b64e99a1
--- /dev/null
+++ b/plc4go/internal/eip/Writer.go
@@ -0,0 +1,361 @@
+/*
+ * 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 eip
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	plc4goModel "github.com/apache/plc4x/plc4go/internal/spi/model"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go/values"
+	readWriteModel "github.com/apache/plc4x/plc4go/protocols/eip/readwrite/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+	"strings"
+	"time"
+)
+
+type Writer struct {
+	messageCodec  spi.MessageCodec
+	tm            *spi.RequestTransactionManager
+	configuration Configuration
+	sessionHandle *uint32
+	senderContext *[]uint8
+}
+
+func NewWriter(messageCodec spi.MessageCodec, tm *spi.RequestTransactionManager, configuration Configuration, sessionHandle *uint32, senderContext *[]uint8) Writer {
+	return Writer{
+		messageCodec:  messageCodec,
+		tm:            tm,
+		configuration: configuration,
+		sessionHandle: sessionHandle,
+		senderContext: senderContext,
+	}
+}
+
+func (m Writer) Write(writeRequest model.PlcWriteRequest) <-chan model.PlcWriteRequestResult {
+	result := make(chan model.PlcWriteRequestResult)
+	go func() {
+		items := make([]*readWriteModel.CipService, len(writeRequest.GetFieldNames()))
+		for i, fieldName := range writeRequest.GetFieldNames() {
+			field := writeRequest.GetField(fieldName).(EIPPlcField)
+			value := writeRequest.GetValue(fieldName)
+			tag := field.GetTag()
+			elements := uint16(1)
+			if field.GetElementNb() > 1 {
+				elements = field.GetElementNb()
+			}
+			// We need the size of the request in words (0x91, tagLength, ... tag + possible pad)
+			// Taking half to get word size
+			isArray := false
+			tagIsolated := tag
+			if strings.Contains(tag, "[") {
+				isArray = true
+				tagIsolated = tag[:strings.Index(tag, "[")]
+			}
+			dataLength := len(tagIsolated) + 2 + (len(tagIsolated) % 2)
+			if isArray {
+				dataLength += 2
+			}
+			requestPathSize := int8(dataLength / 2)
+			data, err := encodeValue(value, field.GetType(), elements)
+			if err != nil {
+				result <- &plc4goModel.DefaultPlcWriteRequestResult{
+					Request:  writeRequest,
+					Response: nil,
+					Err:      errors.Wrapf(err, "Error encoding value for field %s", fieldName),
+				}
+				return
+			}
+			ansi, err := toAnsi(tag)
+			if err != nil {
+				result <- &plc4goModel.DefaultPlcWriteRequestResult{
+					Request:  writeRequest,
+					Response: nil,
+					Err:      errors.Wrapf(err, "Error encoding eip ansi for field %s", fieldName),
+				}
+				return
+			}
+			items[i] = readWriteModel.NewCipWriteRequest(requestPathSize, ansi, field.GetType(), elements, data, 0).GetParent()
+		}
+
+		if len(items) == 1 {
+			// Assemble the finished paket
+			log.Trace().Msg("Assemble paket")
+			pkt := readWriteModel.NewCipRRData(
+				readWriteModel.NewCipExchange(
+					readWriteModel.NewCipUnconnectedRequest(
+						items[0],
+						m.configuration.backplane,
+						m.configuration.slot,
+						0,
+					).GetParent(),
+					0,
+				),
+				*m.sessionHandle,
+				0,
+				*m.senderContext,
+				0,
+				0,
+			)
+			// Start a new request-transaction (Is ended in the response-handler)
+			transaction := m.tm.StartTransaction()
+			transaction.Submit(func() {
+				// Send the  over the wire
+				if err := m.messageCodec.SendRequest(
+					pkt,
+					func(message interface{}) bool {
+						eipPacket := readWriteModel.CastEipPacket(message)
+						if eipPacket == nil {
+							return false
+						}
+						cipRRData := readWriteModel.CastCipRRData(eipPacket.Child)
+						if cipRRData == nil {
+							return false
+						}
+						if eipPacket.SessionHandle != *m.sessionHandle {
+							return false
+						}
+						cipWriteResponse := readWriteModel.CastCipWriteResponse(cipRRData.Exchange.Service)
+						if cipWriteResponse == nil {
+							return false
+						}
+						return true
+					},
+					func(message interface{}) error {
+						// Convert the response into an
+						log.Trace().Msg("convert response to ")
+						eipPacket := readWriteModel.CastEipPacket(message)
+						cipRRData := readWriteModel.CastCipRRData(eipPacket.Child)
+						cipWriteResponse := readWriteModel.CastCipWriteResponse(cipRRData.Exchange.Service)
+						// Convert the eip response into a PLC4X response
+						log.Trace().Msg("convert response to PLC4X response")
+						readResponse, err := m.ToPlc4xWriteResponse(cipWriteResponse.CipService, writeRequest)
+
+						if err != nil {
+							result <- &plc4goModel.DefaultPlcWriteRequestResult{
+								Request: writeRequest,
+								Err:     errors.Wrap(err, "Error decoding response"),
+							}
+							return transaction.EndRequest()
+						}
+						result <- &plc4goModel.DefaultPlcWriteRequestResult{
+							Request:  writeRequest,
+							Response: readResponse,
+						}
+						return transaction.EndRequest()
+					},
+					func(err error) error {
+						result <- &plc4goModel.DefaultPlcWriteRequestResult{
+							Request: writeRequest,
+							Err:     errors.New("got timeout while waiting for response"),
+						}
+						return transaction.EndRequest()
+					},
+					time.Second*1); err != nil {
+					result <- &plc4goModel.DefaultPlcWriteRequestResult{
+						Request:  writeRequest,
+						Response: nil,
+						Err:      errors.Wrap(err, "error sending message"),
+					}
+					_ = transaction.EndRequest()
+				}
+			})
+		} else {
+			nb := uint16(len(items))
+			offsets := make([]uint16, nb)
+			offset := 2 + nb*2
+			for i := uint16(0); i < nb; i++ {
+				offsets[i] = offset
+				offset += items[i].GetLengthInBytes()
+			}
+
+			serviceArr := make([]*readWriteModel.CipService, nb)
+			for i := uint16(0); i < nb; i++ {
+				serviceArr[i] = items[i]
+			}
+
+			data := readWriteModel.NewServices(nb, offsets, serviceArr, 0)
+
+			// Assemble the finished paket
+			log.Trace().Msg("Assemble paket")
+			pkt := readWriteModel.NewCipRRData(
+				readWriteModel.NewCipExchange(
+					readWriteModel.NewCipUnconnectedRequest(
+						readWriteModel.NewMultipleServiceRequest(data, 0).GetParent(),
+						m.configuration.backplane,
+						m.configuration.slot,
+						0,
+					).GetParent(),
+					0,
+				),
+				*m.sessionHandle,
+				0,
+				*m.senderContext,
+				0,
+				0,
+			)
+			// Start a new request-transaction (Is ended in the response-handler)
+			transaction := m.tm.StartTransaction()
+			transaction.Submit(func() {
+				// Send the  over the wire
+				if err := m.messageCodec.SendRequest(
+					pkt,
+					func(message interface{}) bool {
+						eipPacket := readWriteModel.CastEipPacket(message)
+						if eipPacket == nil {
+							return false
+						}
+						cipRRData := readWriteModel.CastCipRRData(eipPacket.Child)
+						if cipRRData == nil {
+							return false
+						}
+						if eipPacket.SessionHandle != *m.sessionHandle {
+							return false
+						}
+						multipleServiceResponse := readWriteModel.CastMultipleServiceResponse(cipRRData.Exchange.Service)
+						if multipleServiceResponse == nil {
+							return false
+						}
+						if multipleServiceResponse.ServiceNb != nb {
+							return false
+						}
+						return true
+					},
+					func(message interface{}) error {
+						// Convert the response into an
+						log.Trace().Msg("convert response to ")
+						eipPacket := readWriteModel.CastEipPacket(message)
+						cipRRData := readWriteModel.CastCipRRData(eipPacket.Child)
+						multipleServiceResponse := readWriteModel.CastMultipleServiceResponse(cipRRData.Exchange.Service)
+						// Convert the eip response into a PLC4X response
+						log.Trace().Msg("convert response to PLC4X response")
+						readResponse, err := m.ToPlc4xWriteResponse(multipleServiceResponse.CipService, writeRequest)
+
+						if err != nil {
+							result <- &plc4goModel.DefaultPlcWriteRequestResult{
+								Request: writeRequest,
+								Err:     errors.Wrap(err, "Error decoding response"),
+							}
+							return transaction.EndRequest()
+						}
+						result <- &plc4goModel.DefaultPlcWriteRequestResult{
+							Request:  writeRequest,
+							Response: readResponse,
+						}
+						return transaction.EndRequest()
+					},
+					func(err error) error {
+						result <- &plc4goModel.DefaultPlcWriteRequestResult{
+							Request: writeRequest,
+							Err:     errors.New("got timeout while waiting for response"),
+						}
+						return transaction.EndRequest()
+					},
+					time.Second*1); err != nil {
+					result <- &plc4goModel.DefaultPlcWriteRequestResult{
+						Request:  writeRequest,
+						Response: nil,
+						Err:      errors.Wrap(err, "error sending message"),
+					}
+					_ = transaction.EndRequest()
+				}
+			})
+		}
+	}()
+	return result
+}
+
+func encodeValue(value values.PlcValue, _type readWriteModel.CIPDataTypeCode, elements uint16) ([]byte, error) {
+	buffer := utils.NewLittleEndianWriteBufferByteBased()
+	switch _type {
+	case readWriteModel.CIPDataTypeCode_SINT:
+		err := buffer.WriteByte("", value.GetUint8())
+		if err != nil {
+			return nil, err
+		}
+	case readWriteModel.CIPDataTypeCode_INT:
+		err := buffer.WriteInt16("", 16, value.GetInt16())
+		if err != nil {
+			return nil, err
+		}
+	case readWriteModel.CIPDataTypeCode_DINT:
+		err := buffer.WriteInt32("", 32, value.GetInt32())
+		if err != nil {
+			return nil, err
+		}
+	case readWriteModel.CIPDataTypeCode_REAL:
+		err := buffer.WriteFloat64("", 64, value.GetFloat64())
+		if err != nil {
+			return nil, err
+		}
+	default:
+		// TODO: what is the default type? write nothing?
+		//panic("unmapped type: " + strconv.Itoa(int(_type)))
+	}
+	return buffer.GetBytes(), nil
+}
+
+func (m Writer) ToPlc4xWriteResponse(response *readWriteModel.CipService, writeRequest model.PlcWriteRequest) (model.PlcWriteResponse, error) {
+	responseCodes := map[string]model.PlcResponseCode{}
+	switch response.Child.(type) {
+	case *readWriteModel.CipWriteResponse: // only 1 field
+		cipReadResponse := response.Child.(*readWriteModel.CipWriteResponse)
+		fieldName := writeRequest.GetFieldNames()[0]
+		code := decodeResponseCode(cipReadResponse.Status)
+		responseCodes[fieldName] = code
+	case *readWriteModel.MultipleServiceResponse: //Multiple response
+		multipleServiceResponse := response.Child.(*readWriteModel.MultipleServiceResponse)
+		nb := multipleServiceResponse.ServiceNb
+		arr := make([]*readWriteModel.CipService, nb)
+		read := utils.NewLittleEndianReadBufferByteBased(multipleServiceResponse.ServicesData)
+		total := read.GetTotalBytes()
+		for i := uint16(0); i < nb; i++ {
+			length := uint16(0)
+			offset := multipleServiceResponse.Offsets[i] - multipleServiceResponse.Offsets[0] //Substract first offset as we only have the service in the buffer (not servicesNb and offsets)
+			if i == nb-1 {
+				length = uint16(total) - offset //Get the rest if last
+			} else {
+				length = multipleServiceResponse.Offsets[i+1] - offset - multipleServiceResponse.Offsets[0] //Calculate length with offsets (substracting first offset)
+			}
+			serviceBuf := utils.NewLittleEndianReadBufferByteBased(read.GetBytes()[offset : offset+length])
+			var err error
+			arr[i], err = readWriteModel.CipServiceParse(serviceBuf, length)
+			if err != nil {
+				return nil, err
+			}
+		}
+		services := readWriteModel.NewServices(nb, multipleServiceResponse.Offsets, arr, 0)
+		for i, fieldName := range writeRequest.GetFieldNames() {
+			if writeResponse, ok := services.Services[i].Child.(*readWriteModel.CipWriteResponse); ok {
+				code := decodeResponseCode(writeResponse.Status)
+				responseCodes[fieldName] = code
+			} else {
+				responseCodes[fieldName] = model.PlcResponseCode_INTERNAL_ERROR
+			}
+		}
+	default:
+		return nil, errors.Errorf("unsupported response type %T", response.Child)
+	}
+
+	// Return the response
+	log.Trace().Msg("Returning the response")
+	return plc4goModel.NewDefaultPlcWriteResponse(writeRequest, responseCodes), nil
+}
diff --git a/plc4go/internal/knxnetip/Browser.go b/plc4go/internal/knxnetip/Browser.go
new file mode 100644
index 0000000000..ab0c3eb90c
--- /dev/null
+++ b/plc4go/internal/knxnetip/Browser.go
@@ -0,0 +1,703 @@
+/*
+ * 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 knxnetip
+
+import (
+	"encoding/hex"
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	"github.com/apache/plc4x/plc4go/internal/spi/model"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	apiModel "github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go/values"
+	driverModel "github.com/apache/plc4x/plc4go/protocols/knxnetip/readwrite/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+)
+
+type Browser struct {
+	connection      *Connection
+	messageCodec    spi.MessageCodec
+	sequenceCounter uint8
+}
+
+func NewBrowser(connection *Connection, messageCodec spi.MessageCodec) *Browser {
+	return &Browser{
+		connection:      connection,
+		messageCodec:    messageCodec,
+		sequenceCounter: 0,
+	}
+}
+
+func (m Browser) Browse(browseRequest apiModel.PlcBrowseRequest) <-chan apiModel.PlcBrowseRequestResult {
+	return m.BrowseWithInterceptor(browseRequest, func(result apiModel.PlcBrowseEvent) bool {
+		return true
+	})
+}
+
+func (m Browser) BrowseWithInterceptor(browseRequest apiModel.PlcBrowseRequest, interceptor func(result apiModel.PlcBrowseEvent) bool) <-chan apiModel.PlcBrowseRequestResult {
+	result := make(chan apiModel.PlcBrowseRequestResult)
+	sendResult := func(browseResponse apiModel.PlcBrowseResponse, err error) {
+		result <- &model.DefaultPlcBrowseRequestResult{
+			Request:  browseRequest,
+			Response: browseResponse,
+			Err:      err,
+		}
+	}
+
+	go func() {
+		results := map[string][]apiModel.PlcBrowseQueryResult{}
+		for _, queryName := range browseRequest.GetQueryNames() {
+			queryString := browseRequest.GetQueryString(queryName)
+			field, err := m.connection.fieldHandler.ParseQuery(queryString)
+			if err != nil {
+				sendResult(nil, err)
+				return
+			}
+
+			switch field.(type) {
+			case DeviceQueryField:
+				queryResults, err := m.executeDeviceQuery(field.(DeviceQueryField), browseRequest, queryName, interceptor)
+				if err != nil {
+					// TODO: Return some sort of return code like with the read and write APIs
+					results[queryName] = nil
+				} else {
+					results[queryName] = queryResults
+				}
+			case CommunicationObjectQueryField:
+				queryResults, err := m.executeCommunicationObjectQuery(field.(CommunicationObjectQueryField))
+				if err != nil {
+					// TODO: Return some sort of return code like with the read and write APIs
+					results[queryName] = nil
+				} else {
+					results[queryName] = queryResults
+				}
+			default:
+				// TODO: Return some sort of return code like with the read and write APIs
+				results[queryName] = nil
+			}
+		}
+		sendResult(model.NewDefaultPlcBrowseResponse(browseRequest, results), nil)
+	}()
+	return result
+}
+
+func (m Browser) executeDeviceQuery(field DeviceQueryField, browseRequest apiModel.PlcBrowseRequest, queryName string, interceptor func(result apiModel.PlcBrowseEvent) bool) ([]apiModel.PlcBrowseQueryResult, error) {
+	// Create a list of address strings, which doesn't contain any ranges, lists or wildcards
+	knxAddresses, err := m.calculateAddresses(field)
+	if err != nil {
+		return nil, err
+	}
+	if len(knxAddresses) == 0 {
+		return nil, errors.New("query resulted in not a single valid address")
+	}
+
+	var queryResults []apiModel.PlcBrowseQueryResult
+	// Parse each of these expanded addresses and handle them accordingly.
+	for _, knxAddress := range knxAddresses {
+		// Send a connection request to the device
+		connectTtlTimer := time.NewTimer(m.connection.defaultTtl)
+		deviceConnections := m.connection.DeviceConnect(knxAddress)
+		select {
+		case deviceConnection := <-deviceConnections:
+			if !connectTtlTimer.Stop() {
+				<-connectTtlTimer.C
+			}
+			// If the request returned a connection, process it,
+			// otherwise just ignore it.
+			if deviceConnection.connection != nil {
+				queryResult := &model.DefaultPlcBrowseQueryResult{
+					Field: NewDeviceQueryField(
+						strconv.Itoa(int(knxAddress.MainGroup)),
+						strconv.Itoa(int(knxAddress.MiddleGroup)),
+						strconv.Itoa(int(knxAddress.SubGroup)),
+					),
+					PossibleDataTypes: nil,
+				}
+
+				// Pass it to the callback
+				add := true
+				if interceptor != nil {
+					add = interceptor(&model.DefaultPlcBrowseEvent{
+						Request:   browseRequest,
+						QueryName: queryName,
+						Result:    queryResult,
+						Err:       nil,
+					})
+				}
+
+				// If the interceptor opted for adding it to the result, do so
+				if add {
+					queryResults = append(queryResults, queryResult)
+				}
+
+				disconnectTtlTimer := time.NewTimer(m.connection.defaultTtl * 10)
+				deviceDisconnections := m.connection.DeviceDisconnect(knxAddress)
+				select {
+				case _ = <-deviceDisconnections:
+					if !disconnectTtlTimer.Stop() {
+						<-disconnectTtlTimer.C
+					}
+				case <-disconnectTtlTimer.C:
+					disconnectTtlTimer.Stop()
+					// Just ignore this case ...
+				}
+			}
+		case <-connectTtlTimer.C:
+			connectTtlTimer.Stop()
+			// In this case the remote was just not responding.
+		}
+		// Just to slow things down a bit (This way we can't exceed the max number of requests per minute)
+		//time.Sleep(time.Millisecond * 20)
+	}
+	return queryResults, nil
+}
+
+func (m Browser) executeCommunicationObjectQuery(field CommunicationObjectQueryField) ([]apiModel.PlcBrowseQueryResult, error) {
+	var results []apiModel.PlcBrowseQueryResult
+
+	knxAddress := field.toKnxAddress()
+	knxAddressString := KnxAddressToString(knxAddress)
+
+	// If we have a building Key, try that to login in order to access protected
+	if m.connection.buildingKey != nil {
+		arr := m.connection.DeviceAuthenticate(*knxAddress, m.connection.buildingKey)
+		<-arr
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////////////////////////
+	// Group Address Table reading
+	/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	// First, request the starting address of the group address table
+	readRequestBuilder := m.connection.ReadRequestBuilder()
+	readRequestBuilder.AddQuery("groupAddressTableAddress", knxAddressString+"#1/7")
+	readRequest, err := readRequestBuilder.Build()
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating read request")
+	}
+	rrr := readRequest.Execute()
+	readResult := <-rrr
+	if readResult.GetErr() != nil {
+		return nil, errors.Wrap(readResult.GetErr(), "error reading the group address table starting address:")
+	}
+	if readResult.GetResponse().GetResponseCode("groupAddressTableAddress") != apiModel.PlcResponseCode_OK {
+		return nil, errors.Errorf("error reading group address table starting address: %s",
+			readResult.GetResponse().GetResponseCode("groupAddressTableAddress").GetName())
+	}
+	groupAddressTableStartAddress := readResult.GetResponse().GetValue("groupAddressTableAddress").GetUint32()
+
+	// Then read one byte at the given location.
+	// This will return the number of entries in the group address table (each 2 bytes)
+	readRequestBuilder = m.connection.ReadRequestBuilder()
+	// Depending on the type of device, query an USINT (1 byte) or UINT (2 bytes)
+	// TODO: Do this correctly depending on the device connection device-descriptor
+	if m.connection.DeviceConnections[*knxAddress].deviceDescriptor == uint16(0x07B0) /* SystemB */ {
+		readRequestBuilder.AddQuery("numberOfAddressTableEntries",
+			fmt.Sprintf("%s#%X:UINT", knxAddressString, groupAddressTableStartAddress))
+	} else {
+		readRequestBuilder.AddQuery("numberOfAddressTableEntries",
+			fmt.Sprintf("%s#%X:USINT", knxAddressString, groupAddressTableStartAddress))
+	}
+	readRequest, err = readRequestBuilder.Build()
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating read request")
+	}
+	rrr = readRequest.Execute()
+	readResult = <-rrr
+	if readResult.GetErr() != nil {
+		return nil, errors.Wrap(readResult.GetErr(), "error reading the number of group address table entries")
+	}
+	if readResult.GetResponse().GetResponseCode("numberOfAddressTableEntries") != apiModel.PlcResponseCode_OK {
+		return nil, errors.Errorf("error reading the number of group address table entries: %s",
+			readResult.GetResponse().GetResponseCode("numberOfAddressTableEntries").GetName())
+	}
+	numGroupAddresses := readResult.GetResponse().GetValue("numberOfAddressTableEntries").GetUint16()
+
+	if m.connection.DeviceConnections[*knxAddress].deviceDescriptor == uint16(0x07B0) /* SystemB */ {
+		groupAddressTableStartAddress += 2
+	} else {
+		groupAddressTableStartAddress += 3
+		numGroupAddresses--
+	}
+
+	// Abort, if there aren't any addresses to read.
+	if numGroupAddresses == 0 {
+		return results, nil
+	}
+
+	// Read the data in the group address table
+	readRequest, err = m.connection.ReadRequestBuilder().
+		AddQuery("groupAddressTable",
+			fmt.Sprintf("%s#%X:UINT[%d]", knxAddressString, groupAddressTableStartAddress, numGroupAddresses)).
+		Build()
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating read request")
+	}
+	rrr = readRequest.Execute()
+	readResult = <-rrr
+	if readResult.GetErr() != nil {
+		return nil, errors.Wrap(readResult.GetErr(), "error reading the group address table content")
+	}
+	if (readResult.GetResponse() == nil) ||
+		(readResult.GetResponse().GetResponseCode("groupAddressTable") != apiModel.PlcResponseCode_OK) {
+		return nil, errors.Errorf("error reading the group address table content: %s",
+			readResult.GetResponse().GetResponseCode("groupAddressTable").GetName())
+	}
+	var knxGroupAddresses []*driverModel.KnxGroupAddress
+	if readResult.GetResponse().GetValue("groupAddressTable").IsList() {
+		for _, groupAddress := range readResult.GetResponse().GetValue("groupAddressTable").GetList() {
+			groupAddress := Uint16ToKnxGroupAddress(groupAddress.GetUint16(), 3)
+			knxGroupAddresses = append(knxGroupAddresses, groupAddress)
+		}
+	} else {
+		groupAddress := Uint16ToKnxGroupAddress(readResult.GetResponse().GetValue("groupAddressTable").GetUint16(), 3)
+		knxGroupAddresses = append(knxGroupAddresses, groupAddress)
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////////////////////////
+	// Group Address Association Table reading
+	/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	// Now we read the group address association table address
+	readRequestBuilder = m.connection.ReadRequestBuilder()
+	readRequestBuilder.AddQuery("groupAddressAssociationTableAddress",
+		fmt.Sprintf("%s#2/7", knxAddressString))
+	readRequest, err = readRequestBuilder.Build()
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating read request")
+	}
+	rrr = readRequest.Execute()
+	readResult = <-rrr
+	if readResult.GetErr() != nil {
+		return nil, errors.Wrap(readResult.GetErr(), "error reading the group address association table address")
+	}
+	if (readResult.GetResponse() != nil) &&
+		(readResult.GetResponse().GetResponseCode("groupAddressAssociationTableAddress") != apiModel.PlcResponseCode_OK) {
+		return nil, errors.Errorf("error reading the group address association table address: %s",
+			readResult.GetResponse().GetResponseCode("groupAddressAssociationTableAddress").GetName())
+	}
+	groupAddressAssociationTableAddress := readResult.GetResponse().GetValue("groupAddressAssociationTableAddress").GetUint16()
+
+	// Then read one uint16 at the given location.
+	// This will return the number of entries in the group address table (each 2 bytes)
+	readRequestBuilder = m.connection.ReadRequestBuilder()
+	if m.connection.DeviceConnections[*knxAddress].deviceDescriptor == uint16(0x07B0) /* SystemB */ {
+		readRequestBuilder.AddQuery("numberOfGroupAddressAssociationTableEntries",
+			fmt.Sprintf("%s#%X:UINT", knxAddressString, groupAddressAssociationTableAddress))
+	} else {
+		readRequestBuilder.AddQuery("numberOfGroupAddressAssociationTableEntries",
+			fmt.Sprintf("%s#%X:USINT", knxAddressString, groupAddressAssociationTableAddress))
+	}
+	readRequest, err = readRequestBuilder.Build()
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating read request")
+	}
+	rrr = readRequest.Execute()
+	readResult = <-rrr
+	if readResult.GetErr() != nil {
+		return nil, errors.Wrap(readResult.GetErr(), "error reading the number of group address association table entries")
+	}
+	if (readResult.GetResponse() != nil) &&
+		(readResult.GetResponse().GetResponseCode("numberOfGroupAddressAssociationTableEntries") != apiModel.PlcResponseCode_OK) {
+		return nil, errors.Errorf("error reading the number of group address association table entries: %s",
+			readResult.GetResponse().GetResponseCode("numberOfGroupAddressAssociationTableEntries").GetName())
+	}
+	numberOfGroupAddressAssociationTableEntries := readResult.GetResponse().GetValue("numberOfGroupAddressAssociationTableEntries").GetUint16()
+
+	// Read the data in the group address table
+	readRequestBuilder = m.connection.ReadRequestBuilder()
+	// TODO: This request needs to be automatically split up into multiple requests.
+	// Reasons for splitting up:
+	// - Max APDU Size exceeded
+	// - Max 63 bytes readable in one request, due to max of count field
+	if m.connection.DeviceConnections[*knxAddress].deviceDescriptor == uint16(0x07B0) /* SystemB */ {
+		readRequestBuilder.AddQuery("groupAddressAssociationTable",
+			fmt.Sprintf("%s#%X:UDINT[%d]", knxAddressString, groupAddressAssociationTableAddress+2, numberOfGroupAddressAssociationTableEntries))
+	} else {
+		readRequestBuilder.AddQuery("groupAddressAssociationTable",
+			fmt.Sprintf("%s#%X:UINT[%d]", knxAddressString, groupAddressAssociationTableAddress+1, numberOfGroupAddressAssociationTableEntries))
+	}
+	readRequest, err = readRequestBuilder.Build()
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating read request")
+	}
+	rrr = readRequest.Execute()
+	readResult = <-rrr
+	if readResult.GetErr() != nil {
+		return nil, errors.Wrap(readResult.GetErr(), "error reading the group address association table content")
+	}
+	if (readResult.GetResponse() != nil) &&
+		(readResult.GetResponse().GetResponseCode("groupAddressAssociationTable") != apiModel.PlcResponseCode_OK) {
+		return nil, errors.Errorf("error reading the group address association table content: %s",
+			readResult.GetResponse().GetResponseCode("groupAddressAssociationTable").GetName())
+	}
+	// Output the group addresses
+	groupAddressComObjectNumberMapping := map[*driverModel.KnxGroupAddress]uint16{}
+	if readResult.GetResponse().GetValue("groupAddressAssociationTable").IsList() {
+		for _, groupAddressAssociation := range readResult.GetResponse().GetValue("groupAddressAssociationTable").GetList() {
+			groupAddress, comObjectNumber := m.parseAssociationTable(m.connection.DeviceConnections[*knxAddress].deviceDescriptor,
+				knxGroupAddresses, groupAddressAssociation)
+			if groupAddress != nil {
+				groupAddressComObjectNumberMapping[groupAddress] = comObjectNumber
+			}
+		}
+	} else {
+		groupAddress, comObjectNumber := m.parseAssociationTable(m.connection.DeviceConnections[*knxAddress].deviceDescriptor,
+			knxGroupAddresses, readResult.GetResponse().GetValue("groupAddressAssociationTable"))
+		if groupAddress != nil {
+			groupAddressComObjectNumberMapping[groupAddress] = comObjectNumber
+		}
+	}
+
+	/////////////////////////////////////////////////////////////////////////////////////////////////////
+	// Com Object Table reading (Not supported on all devices)
+	// (This part is optional and experimental ...)
+	/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	// In case of System B devices, the com object table is read as a property array
+	// In this case we can even read only the com objects we're interested in.
+	if m.connection.DeviceConnections[*knxAddress].deviceDescriptor == uint16(0x07B0) /* SystemB */ {
+		readRequestBuilder = m.connection.ReadRequestBuilder()
+		// Read data for all com objects that are assigned a group address
+		for _, comObjectNumber := range groupAddressComObjectNumberMapping {
+			readRequestBuilder.AddQuery(strconv.Itoa(int(comObjectNumber)),
+				fmt.Sprintf("%s#3/23/%d", knxAddressString, comObjectNumber))
+		}
+		readRequest, err = readRequestBuilder.Build()
+		if err != nil {
+			return nil, errors.Wrap(err, "error creating read request")
+		}
+		rrr = readRequest.Execute()
+		readResult = <-rrr
+		for groupAddress, comObjectNumber := range groupAddressComObjectNumberMapping {
+			if readResult.GetResponse().GetResponseCode(strconv.Itoa(int(comObjectNumber))) != apiModel.PlcResponseCode_OK {
+				continue
+			}
+			comObjectSettings := readResult.GetResponse().GetValue(strconv.Itoa(int(comObjectNumber))).GetUint16()
+			data := []uint8{uint8((comObjectSettings >> 8) & 0xFF), uint8(comObjectSettings & 0xFF)}
+			rb := utils.NewReadBufferByteBased(data)
+			descriptor, err := driverModel.GroupObjectDescriptorRealisationTypeBParse(rb)
+			if err != nil {
+				log.Info().Err(err).Msg("error parsing com object descriptor")
+				continue
+			}
+
+			// Assemble a PlcBrowseQueryResult
+			var field apiModel.PlcField
+			readable := descriptor.CommunicationEnable && descriptor.ReadEnable
+			writable := descriptor.CommunicationEnable && descriptor.WriteEnable
+			subscribable := descriptor.CommunicationEnable && descriptor.TransmitEnable
+			// Find a matching datatype for the given value-type.
+			fieldType := m.getFieldTypeForValueType(descriptor.ValueType)
+			switch groupAddress.Child.(type) {
+			case *driverModel.KnxGroupAddress3Level:
+				address3Level := driverModel.CastKnxGroupAddress3Level(groupAddress)
+				field = NewGroupAddress3LevelPlcField(strconv.Itoa(int(address3Level.MainGroup)),
+					strconv.Itoa(int(address3Level.MiddleGroup)), strconv.Itoa(int(address3Level.SubGroup)),
+					&fieldType)
+			case *driverModel.KnxGroupAddress2Level:
+				address2Level := driverModel.CastKnxGroupAddress2Level(groupAddress)
+				field = NewGroupAddress2LevelPlcField(strconv.Itoa(int(address2Level.MainGroup)),
+					strconv.Itoa(int(address2Level.SubGroup)),
+					&fieldType)
+			case *driverModel.KnxGroupAddressFreeLevel:
+				address1Level := driverModel.CastKnxGroupAddressFreeLevel(groupAddress)
+				field = NewGroupAddress1LevelPlcField(strconv.Itoa(int(address1Level.SubGroup)),
+					&fieldType)
+			}
+
+			results = append(results, &model.DefaultPlcBrowseQueryResult{
+				Field:             field,
+				Name:              fmt.Sprintf("#%d", comObjectNumber),
+				Readable:          readable,
+				Writable:          writable,
+				Subscribable:      subscribable,
+				PossibleDataTypes: nil,
+			})
+		}
+	} else if (m.connection.DeviceConnections[*knxAddress].deviceDescriptor & 0xFFF0) == uint16(0x0700) /* System7 */ {
+		// For System 7 Devices we unfortunately can't access the information of where the memory address for the
+		// Com Object Table is programmatically, so we have to look up the address which is extracted from the XML data
+		// Provided by the manufacturer. Unfortunately in order to be able to do this, we need to get the application
+		// version from the device first.
+
+		readRequestBuilder = m.connection.ReadRequestBuilder()
+		readRequestBuilder.AddQuery("applicationProgramVersion", knxAddressString+"#3/13")
+		readRequestBuilder.AddQuery("interfaceProgramVersion", knxAddressString+"#4/13")
+		readRequest, err = readRequestBuilder.Build()
+		if err != nil {
+			return nil, errors.Wrap(err, "error creating read request")
+		}
+
+		rrr = readRequest.Execute()
+		readRequestResult := <-rrr
+		readResponse := readRequestResult.GetResponse()
+		var programVersionData []byte
+		if readResponse.GetResponseCode("applicationProgramVersion") == apiModel.PlcResponseCode_OK {
+			programVersionData = utils.PlcValueUint8ListToByteArray(readResponse.GetValue("applicationProgramVersion"))
+		} else if readResponse.GetResponseCode("interfaceProgramVersion") == apiModel.PlcResponseCode_OK {
+			programVersionData = utils.PlcValueUint8ListToByteArray(readResponse.GetValue("interfaceProgramVersion"))
+		}
+		applicationId := hex.EncodeToString(programVersionData)
+
+		// Lookup the com object table address
+		comObjectTableAddresses := driverModel.ComObjectTableAddressesByName("DEV" + strings.ToUpper(applicationId))
+		if comObjectTableAddresses == 0 {
+			return nil, errors.Errorf("error getting com address table address. No table entry for application id: %s", applicationId)
+		}
+
+		readRequestBuilder = m.connection.ReadRequestBuilder()
+		// Read data for all com objects that are assigned a group address
+		groupAddressMap := map[uint16][]*driverModel.KnxGroupAddress{}
+		for groupAddress, comObjectNumber := range groupAddressComObjectNumberMapping {
+			if groupAddressMap[comObjectNumber] == nil {
+				groupAddressMap[comObjectNumber] = []*driverModel.KnxGroupAddress{}
+			}
+			groupAddressMap[comObjectNumber] = append(groupAddressMap[comObjectNumber], groupAddress)
+			entryAddress := comObjectTableAddresses.ComObjectTableAddress() + 3 + (comObjectNumber * 4)
+			readRequestBuilder.AddQuery(strconv.Itoa(int(comObjectNumber)),
+				fmt.Sprintf("%s#%X:USINT[4]", knxAddressString, entryAddress))
+		}
+		readRequest, err = readRequestBuilder.Build()
+		if err != nil {
+			return nil, errors.Wrap(err, "error creating read request")
+		}
+		rrr = readRequest.Execute()
+		readResult = <-rrr
+
+		for _, fieldName := range readResult.GetResponse().GetFieldNames() {
+			array := utils.PlcValueUint8ListToByteArray(readResult.GetResponse().GetValue(fieldName))
+			rb := utils.NewReadBufferByteBased(array)
+			descriptor, err := driverModel.GroupObjectDescriptorRealisationType7Parse(rb)
+			if err != nil {
+				return nil, errors.Wrap(err, "error creating read request")
+			}
+
+			// We saved the com object number in the field name.
+			comObjectNumber, _ := strconv.ParseUint(fieldName, 10, 16)
+			groupAddresses := groupAddressMap[uint16(comObjectNumber)]
+			readable := descriptor.CommunicationEnable && descriptor.ReadEnable
+			writable := descriptor.CommunicationEnable && descriptor.WriteEnable
+			subscribable := descriptor.CommunicationEnable && descriptor.TransmitEnable
+			// Find a matching datatype for the given value-type.
+			fieldType := m.getFieldTypeForValueType(descriptor.ValueType)
+
+			// Create a field for each of the given inputs.
+			for _, groupAddress := range groupAddresses {
+				field := m.getFieldForGroupAddress(groupAddress, fieldType)
+
+				results = append(results, &model.DefaultPlcBrowseQueryResult{
+					Field:             field,
+					Name:              fmt.Sprintf("#%d", comObjectNumber),
+					Readable:          readable,
+					Writable:          writable,
+					Subscribable:      subscribable,
+					PossibleDataTypes: nil,
+				})
+			}
+		}
+	} else {
+		readRequestBuilder = m.connection.ReadRequestBuilder()
+		readRequestBuilder.AddQuery("comObjectTableAddress", fmt.Sprintf("%s#3/7", knxAddressString))
+		readRequest, err = readRequestBuilder.Build()
+		if err != nil {
+			return nil, errors.Wrap(err, "error creating read request")
+		}
+		rrr = readRequest.Execute()
+		readResult = <-rrr
+		if readResult.GetResponse().GetResponseCode("comObjectTableAddress") == apiModel.PlcResponseCode_OK {
+			comObjectTableAddress := readResult.GetResponse().GetValue("comObjectTableAddress").GetUint16()
+			log.Info().Msgf("Com Object Table Address: %x", comObjectTableAddress)
+		}
+	}
+
+	return results, nil
+}
+
+func (m Browser) calculateAddresses(field DeviceQueryField) ([]driverModel.KnxAddress, error) {
+	var explodedAddresses []driverModel.KnxAddress
+	mainGroupOptions, err := m.explodeSegment(field.MainGroup, 1, 15)
+	if err != nil {
+		return nil, err
+	}
+	middleGroupOptions, err := m.explodeSegment(field.MiddleGroup, 1, 15)
+	if err != nil {
+		return nil, err
+	}
+	subGroupOptions, err := m.explodeSegment(field.SubGroup, 0, 255)
+	if err != nil {
+		return nil, err
+	}
+	for _, mainOption := range mainGroupOptions {
+		for _, middleOption := range middleGroupOptions {
+			for _, subOption := range subGroupOptions {
+				// Don't try connecting to ourselves.
+				if m.connection.ClientKnxAddress != nil {
+					currentAddress := driverModel.KnxAddress{
+						MainGroup:   mainOption,
+						MiddleGroup: middleOption,
+						SubGroup:    subOption,
+					}
+					explodedAddresses = append(explodedAddresses, currentAddress)
+				}
+			}
+		}
+	}
+	return explodedAddresses, nil
+}
+
+func (m Browser) explodeSegment(segment string, min uint8, max uint8) ([]uint8, error) {
+	var options []uint8
+	if strings.Contains(segment, "*") {
+		for i := min; i <= max; i++ {
+			options = append(options, i)
+		}
+	} else if strings.HasPrefix(segment, "[") && strings.HasSuffix(segment, "]") {
+		segment = strings.TrimPrefix(segment, "[")
+		segment = strings.TrimSuffix(segment, "]")
+		for _, segment := range strings.Split(segment, ",") {
+			if strings.Contains(segment, "-") {
+				split := strings.Split(segment, "-")
+				localMin, err := strconv.ParseUint(split[0], 10, 8)
+				if err != nil {
+					return nil, err
+				}
+				localMax, err := strconv.ParseUint(split[1], 10, 8)
+				if err != nil {
+					return nil, err
+				}
+				for i := localMin; i <= localMax; i++ {
+					options = append(options, uint8(i))
+				}
+			} else {
+				option, err := strconv.ParseUint(segment, 10, 8)
+				if err != nil {
+					return nil, err
+				}
+				options = append(options, uint8(option))
+			}
+		}
+	} else {
+		value, err := strconv.ParseUint(segment, 10, 8)
+		if err != nil {
+			return nil, err
+		}
+		if uint8(value) >= min && uint8(value) <= max {
+			options = append(options, uint8(value))
+		}
+	}
+	return options, nil
+}
+
+func (m Browser) parseAssociationTable(deviceDescriptor uint16, knxGroupAddresses []*driverModel.KnxGroupAddress, value values.PlcValue) (*driverModel.KnxGroupAddress, uint16) {
+	var addressIndex uint16
+	var comObjectNumber uint16
+	if deviceDescriptor == uint16(0x07B0) /* SystemB */ {
+		addressIndex = uint16((value.GetUint32()>>16)&0xFFFF) - 1
+		comObjectNumber = uint16(value.GetUint32() & 0xFFFF)
+	} else {
+		addressIndex = ((value.GetUint16() >> 8) & 0xFF) - 1
+		comObjectNumber = value.GetUint16() & 0xFF
+	}
+	if addressIndex < uint16(len(knxGroupAddresses)) {
+		groupAddress := knxGroupAddresses[addressIndex]
+		return groupAddress, comObjectNumber
+	}
+	return nil, 0
+}
+
+func (m Browser) getFieldForGroupAddress(groupAddress *driverModel.KnxGroupAddress, datatype driverModel.KnxDatapointType) apiModel.PlcField {
+	switch groupAddress.Child.(type) {
+	case *driverModel.KnxGroupAddress3Level:
+		groupAddress3Level := driverModel.CastKnxGroupAddress3Level(groupAddress)
+		return GroupAddress3LevelPlcField{
+			MainGroup:   strconv.Itoa(int(groupAddress3Level.MainGroup)),
+			MiddleGroup: strconv.Itoa(int(groupAddress3Level.MiddleGroup)),
+			SubGroup:    strconv.Itoa(int(groupAddress3Level.SubGroup)),
+			FieldType:   &datatype,
+		}
+	case *driverModel.KnxGroupAddress2Level:
+		groupAddress2Level := driverModel.CastKnxGroupAddress2Level(groupAddress)
+		return GroupAddress2LevelPlcField{
+			MainGroup: strconv.Itoa(int(groupAddress2Level.MainGroup)),
+			SubGroup:  strconv.Itoa(int(groupAddress2Level.SubGroup)),
+			FieldType: &datatype,
+		}
+	case *driverModel.KnxGroupAddressFreeLevel:
+		groupAddress1Level := driverModel.CastKnxGroupAddressFreeLevel(groupAddress)
+		return GroupAddress1LevelPlcField{
+			MainGroup: strconv.Itoa(int(groupAddress1Level.SubGroup)),
+			FieldType: &datatype,
+		}
+	}
+	return nil
+}
+
+func (m Browser) getFieldTypeForValueType(valueType driverModel.ComObjectValueType) driverModel.KnxDatapointType {
+	switch valueType {
+	case driverModel.ComObjectValueType_BIT1:
+		return driverModel.KnxDatapointType_BOOL
+	case driverModel.ComObjectValueType_BIT2:
+		// Will be an array
+		return driverModel.KnxDatapointType_BOOL
+	case driverModel.ComObjectValueType_BIT3:
+		// Will be an array
+		return driverModel.KnxDatapointType_BOOL
+	case driverModel.ComObjectValueType_BIT4:
+		// Will be an array
+		return driverModel.KnxDatapointType_BOOL
+	case driverModel.ComObjectValueType_BIT5:
+		// Will be an array
+		return driverModel.KnxDatapointType_BOOL
+	case driverModel.ComObjectValueType_BIT6:
+		// Will be an array
+		return driverModel.KnxDatapointType_BOOL
+	case driverModel.ComObjectValueType_BIT7:
+		// Will be an array
+		return driverModel.KnxDatapointType_BOOL
+	case driverModel.ComObjectValueType_BYTE1:
+		return driverModel.KnxDatapointType_USINT
+	case driverModel.ComObjectValueType_BYTE2:
+		return driverModel.KnxDatapointType_UINT
+	case driverModel.ComObjectValueType_BYTE3:
+		return driverModel.KnxDatapointType_UDINT
+	case driverModel.ComObjectValueType_BYTE4:
+		return driverModel.KnxDatapointType_UDINT
+	case driverModel.ComObjectValueType_BYTE6:
+		// Will be an array
+		return driverModel.KnxDatapointType_USINT
+	case driverModel.ComObjectValueType_BYTE8:
+		// Will be an array
+		return driverModel.KnxDatapointType_USINT
+	case driverModel.ComObjectValueType_BYTE10:
+		// Will be an array
+		return driverModel.KnxDatapointType_USINT
+	case driverModel.ComObjectValueType_BYTE14:
+		// Will be an array
+		return driverModel.KnxDatapointType_USINT
+	}
+	// Just return "byte" in any other case.
+	return driverModel.KnxDatapointType_USINT
+}
diff --git a/plc4go/internal/knxnetip/Connection.go b/plc4go/internal/knxnetip/Connection.go
new file mode 100644
index 0000000000..673a95888d
--- /dev/null
+++ b/plc4go/internal/knxnetip/Connection.go
@@ -0,0 +1,494 @@
+/*
+ * 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 knxnetip
+
+import (
+	"bytes"
+	"encoding/hex"
+	"fmt"
+	_default "github.com/apache/plc4x/plc4go/internal/spi/default"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	"github.com/apache/plc4x/plc4go/internal/spi/interceptors"
+	internalModel "github.com/apache/plc4x/plc4go/internal/spi/model"
+	"github.com/apache/plc4x/plc4go/internal/spi/transports"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go"
+	apiModel "github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go/values"
+	driverModel "github.com/apache/plc4x/plc4go/protocols/knxnetip/readwrite/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+)
+
+type ConnectionMetadata struct {
+	KnxMedium         driverModel.KnxMedium
+	GatewayName       string
+	GatewayKnxAddress string
+	ClientKnxAddress  string
+
+	ProjectNumber          uint8
+	InstallationNumber     uint8
+	DeviceSerialNumber     []byte
+	DeviceMulticastAddress []byte
+	DeviceMacAddress       []byte
+	SupportedServices      []string
+}
+
+func (m ConnectionMetadata) GetConnectionAttributes() map[string]string {
+	return map[string]string{
+		"KnxMedium":         m.KnxMedium.String(),
+		"GatewayName":       m.GatewayName,
+		"GatewayKnxAddress": m.GatewayKnxAddress,
+		"ClientKnxAddress":  m.ClientKnxAddress,
+
+		"ProjectNumber":          strconv.Itoa(int(m.ProjectNumber)),
+		"InstallationNumber":     strconv.Itoa(int(m.InstallationNumber)),
+		"DeviceSerialNumber":     utils.ByteArrayToString(m.DeviceSerialNumber, " "),
+		"DeviceMulticastAddress": utils.ByteArrayToString(m.DeviceSerialNumber, "."),
+		"DeviceMacAddress":       utils.ByteArrayToString(m.DeviceSerialNumber, ":"),
+		"SupportedServices":      strings.Join(m.SupportedServices, ", "),
+	}
+}
+
+func (m ConnectionMetadata) CanRead() bool {
+	return true
+}
+
+func (m ConnectionMetadata) CanWrite() bool {
+	return true
+}
+
+func (m ConnectionMetadata) CanSubscribe() bool {
+	return true
+}
+
+func (m ConnectionMetadata) CanBrowse() bool {
+	return true
+}
+
+type KnxDeviceConnection struct {
+	counter          uint8
+	deviceDescriptor uint16
+	maxApdu          uint16
+}
+
+type KnxMemoryReadFragment struct {
+	numElements     uint8
+	startingAddress uint16
+}
+
+type Connection struct {
+	messageCodec             spi.MessageCodec
+	options                  map[string][]string
+	fieldHandler             spi.PlcFieldHandler
+	valueHandler             spi.PlcValueHandler
+	connectionStateTimer     *time.Ticker
+	quitConnectionStateTimer chan struct{}
+	subscribers              []*Subscriber
+
+	valueCache      map[uint16][]byte
+	valueCacheMutex sync.RWMutex
+	metadata        *ConnectionMetadata
+	defaultTtl      time.Duration
+	connectionTtl   time.Duration
+	buildingKey     []byte
+
+	// Used for detecting connection problems
+	connectionTimeoutTimer *time.Timer
+
+	GatewayKnxAddress             *driverModel.KnxAddress
+	ClientKnxAddress              *driverModel.KnxAddress
+	CommunicationChannelId        uint8
+	SequenceCounter               int32
+	TunnelingRequestExpectationId int32
+	DeviceConnections             map[driverModel.KnxAddress]*KnxDeviceConnection
+
+	requestInterceptor interceptors.RequestInterceptor
+	sync.Mutex
+
+	// indicates if the tunneling requests loop is running
+	handleTunnelingRequests bool
+
+	connectionId string
+	tracer       *spi.Tracer
+}
+
+func (m *Connection) String() string {
+	return fmt.Sprintf("knx.Connection{}")
+}
+
+type KnxReadResult struct {
+	value    *values.PlcValue
+	numItems uint8
+	err      error
+}
+
+type KnxDeviceConnectResult struct {
+	connection *KnxDeviceConnection
+	err        error
+}
+
+type KnxDeviceDisconnectResult struct {
+	connection *KnxDeviceConnection
+	err        error
+}
+
+type KnxDeviceAuthenticateResult struct {
+	err error
+}
+
+type InternalResult struct {
+	responseMessage interface{}
+	err             error
+}
+
+func NewConnection(transportInstance transports.TransportInstance, options map[string][]string, fieldHandler spi.PlcFieldHandler) *Connection {
+	connection := &Connection{
+		options:      options,
+		fieldHandler: fieldHandler,
+		valueHandler: NewValueHandler(),
+		requestInterceptor: interceptors.NewSingleItemRequestInterceptor(
+			internalModel.NewDefaultPlcReadRequest,
+			internalModel.NewDefaultPlcWriteRequest,
+			internalModel.NewDefaultPlcReadResponse,
+			internalModel.NewDefaultPlcWriteResponse,
+		),
+		subscribers:             []*Subscriber{},
+		valueCache:              map[uint16][]byte{},
+		valueCacheMutex:         sync.RWMutex{},
+		metadata:                &ConnectionMetadata{},
+		defaultTtl:              time.Second * 10,
+		DeviceConnections:       map[driverModel.KnxAddress]*KnxDeviceConnection{},
+		handleTunnelingRequests: true,
+	}
+	connection.connectionTtl = connection.defaultTtl * 2
+
+	if traceEnabledOption, ok := options["traceEnabled"]; ok {
+		if len(traceEnabledOption) == 1 {
+			connection.tracer = spi.NewTracer(connection.connectionId)
+		}
+	}
+	// If a building key was provided, save that in a dedicated variable
+	if buildingKey, ok := options["buildingKey"]; ok {
+		bc, err := hex.DecodeString(buildingKey[0])
+		if err == nil {
+			connection.buildingKey = bc
+		}
+	}
+	connection.messageCodec = NewMessageCodec(transportInstance, connection.interceptIncomingMessage)
+	return connection
+}
+
+func (m *Connection) GetConnectionId() string {
+	return m.connectionId
+}
+
+func (m *Connection) IsTraceEnabled() bool {
+	return m.tracer != nil
+}
+
+func (m *Connection) GetTracer() *spi.Tracer {
+	return m.tracer
+}
+
+func (m *Connection) Connect() <-chan plc4go.PlcConnectionConnectResult {
+	result := make(chan plc4go.PlcConnectionConnectResult)
+	sendResult := func(connection plc4go.PlcConnection, err error) {
+		result <- _default.NewDefaultPlcConnectionConnectResult(connection, err)
+	}
+
+	go func() {
+		// Open the UDP Connection
+		err := m.messageCodec.Connect()
+		if err != nil {
+			m.doSomethingAndClose(func() { sendResult(nil, errors.Wrap(err, "error opening connection")) })
+			return
+		}
+
+		// Send a search request before connecting to the device.
+		searchResponse, err := m.sendGatewaySearchRequest()
+		if err != nil {
+			m.doSomethingAndClose(func() { sendResult(nil, errors.Wrap(err, "error discovering device capabilities")) })
+			return
+		}
+
+		// Save some important information
+		m.metadata.KnxMedium = searchResponse.DibDeviceInfo.KnxMedium
+		m.metadata.GatewayName = string(bytes.Trim(searchResponse.DibDeviceInfo.DeviceFriendlyName, "\x00"))
+		m.GatewayKnxAddress = searchResponse.DibDeviceInfo.KnxAddress
+		m.metadata.GatewayKnxAddress = KnxAddressToString(m.GatewayKnxAddress)
+		m.metadata.ProjectNumber = searchResponse.DibDeviceInfo.ProjectInstallationIdentifier.ProjectNumber
+		m.metadata.InstallationNumber = searchResponse.DibDeviceInfo.ProjectInstallationIdentifier.InstallationNumber
+		m.metadata.DeviceSerialNumber = searchResponse.DibDeviceInfo.KnxNetIpDeviceSerialNumber
+		m.metadata.DeviceMulticastAddress = searchResponse.DibDeviceInfo.KnxNetIpDeviceMulticastAddress.Addr
+		m.metadata.DeviceMacAddress = searchResponse.DibDeviceInfo.KnxNetIpDeviceMacAddress.Addr
+		m.metadata.SupportedServices = []string{}
+		supportsTunneling := false
+		for _, serviceId := range searchResponse.DibSuppSvcFamilies.ServiceIds {
+			m.metadata.SupportedServices = append(m.metadata.SupportedServices, serviceId.Child.GetTypeName())
+			// If this is an instance of the "tunneling", service, this connection supports tunneling
+			_, ok := serviceId.Child.(*driverModel.KnxNetIpTunneling)
+			if ok {
+				supportsTunneling = true
+				break
+			}
+		}
+
+		// If the current device supports tunneling, create a tunneling connection.
+		// Via this connection we then get access to the entire KNX network this Gateway is connected to.
+		if supportsTunneling {
+			// As soon as we got a successful search-response back, send a connection request.
+			connectionResponse, err := m.sendGatewayConnectionRequest()
+			if err != nil {
+				m.doSomethingAndClose(func() { sendResult(nil, errors.Wrap(err, "error connecting to device")) })
+				return
+			}
+
+			// Save the communication channel id
+			m.CommunicationChannelId = connectionResponse.CommunicationChannelId
+
+			// Reset the sequence counter
+			m.SequenceCounter = -1
+
+			// If the connection was successful, the gateway will now forward any packets
+			// on the KNX bus that are broadcast packets to us, so we have to setup things
+			// to handle these incoming messages.
+			switch connectionResponse.Status {
+			case driverModel.Status_NO_ERROR:
+				// Save the KNX Address the Gateway assigned to us for this connection.
+				tunnelConnectionDataBlock := driverModel.CastConnectionResponseDataBlockTunnelConnection(
+					connectionResponse.ConnectionResponseDataBlock,
+				)
+				m.ClientKnxAddress = tunnelConnectionDataBlock.KnxAddress
+
+				// Create a go routine to handle incoming tunneling-requests which haven't been
+				// handled by any other handler. This is where usually the GroupValueWrite messages
+				// are being handled.
+				log.Debug().Msg("Starting tunneling handler")
+				go func() {
+					defaultIncomingMessageChannel := m.messageCodec.GetDefaultIncomingMessageChannel()
+					for m.handleTunnelingRequests {
+						incomingMessage := <-defaultIncomingMessageChannel
+						tunnelingRequest := driverModel.CastTunnelingRequest(incomingMessage)
+						if tunnelingRequest == nil {
+							tunnelingResponse := driverModel.CastTunnelingResponse(incomingMessage)
+							if tunnelingResponse != nil {
+								log.Warn().Msgf("Got an unhandled TunnelingResponse message %v\n", tunnelingResponse)
+							} else {
+								log.Warn().Msgf("Not a TunnelingRequest or TunnelingResponse message %v\n", incomingMessage)
+							}
+							continue
+						}
+
+						if tunnelingRequest.TunnelingRequestDataBlock.CommunicationChannelId != m.CommunicationChannelId {
+							log.Warn().Msgf("Not for this connection %v\n", tunnelingRequest)
+							continue
+						}
+
+						lDataInd := driverModel.CastLDataInd(tunnelingRequest.Cemi)
+						if lDataInd == nil {
+							continue
+						}
+						// Get APDU, source and target address
+						lDataFrameData := driverModel.CastLDataExtended(lDataInd.DataFrame)
+						sourceAddress := lDataFrameData.SourceAddress
+
+						// If this is not an APDU, there is no need to further handle it.
+						if lDataFrameData.Apdu == nil {
+							continue
+						}
+
+						// If this is an incoming disconnect request, remove the device
+						// from the device connections, otherwise handle it as normal
+						// incoming message.
+						apduControlContainer := driverModel.CastApduControlContainer(lDataFrameData.Apdu)
+						if apduControlContainer != nil {
+							disconnectApdu := driverModel.CastApduControlDisconnect(apduControlContainer.ControlApdu)
+							if disconnectApdu != nil {
+								if m.DeviceConnections[*sourceAddress] != nil /* && m.ClientKnxAddress == Int8ArrayToKnxAddress(targetAddress)*/ {
+									// Remove the connection
+									delete(m.DeviceConnections, *sourceAddress)
+								}
+							}
+						} else {
+							m.handleIncomingTunnelingRequest(tunnelingRequest)
+						}
+					}
+					log.Warn().Msg("Tunneling handler shat down")
+				}()
+
+				// Fire the "connected" event
+				sendResult(m, nil)
+			case driverModel.Status_NO_MORE_CONNECTIONS:
+				m.doSomethingAndClose(func() { sendResult(nil, errors.New("no more connections")) })
+			default:
+				m.doSomethingAndClose(func() { sendResult(nil, errors.Errorf("got a return status of: %s", connectionResponse.Status)) })
+			}
+		} else {
+			m.doSomethingAndClose(func() { sendResult(nil, errors.New("this device doesn't support tunneling")) })
+		}
+	}()
+
+	return result
+}
+
+func (m *Connection) doSomethingAndClose(something func()) {
+	something()
+	err := m.messageCodec.Disconnect()
+	if err != nil {
+		log.Warn().Msgf("error closing connection: %s", err)
+	}
+}
+
+func (m *Connection) BlockingClose() {
+	ttlTimer := time.NewTimer(m.defaultTtl)
+	closeResults := m.Close()
+	select {
+	case <-closeResults:
+		if !ttlTimer.Stop() {
+			<-ttlTimer.C
+		}
+		return
+	case <-ttlTimer.C:
+		ttlTimer.Stop()
+		return
+	}
+}
+
+func (m *Connection) Close() <-chan plc4go.PlcConnectionCloseResult {
+	result := make(chan plc4go.PlcConnectionCloseResult)
+
+	go func() {
+		// Stop the connection-state checker.
+		if m.connectionStateTimer != nil {
+			m.connectionStateTimer.Stop()
+		}
+
+		// Disconnect from all knx devices we are still connected to.
+		for targetAddress := range m.DeviceConnections {
+			ttlTimer := time.NewTimer(m.defaultTtl)
+			disconnects := m.DeviceDisconnect(targetAddress)
+			select {
+			case _ = <-disconnects:
+				if !ttlTimer.Stop() {
+					<-ttlTimer.C
+				}
+			case <-ttlTimer.C:
+				ttlTimer.Stop()
+				// If we got a timeout here, well just continue the device will just auto disconnect.
+				log.Debug().Msgf("Timeout disconnecting from device %s.", KnxAddressToString(&targetAddress))
+			}
+		}
+
+		// Send a disconnect request from the gateway.
+		_, err := m.sendGatewayDisconnectionRequest()
+		if err != nil {
+			result <- _default.NewDefaultPlcConnectionCloseResult(m, errors.Wrap(err, "got an error while disconnecting"))
+		} else {
+			result <- _default.NewDefaultPlcConnectionCloseResult(m, nil)
+		}
+	}()
+
+	return result
+}
+
+func (m *Connection) IsConnected() bool {
+	if m.messageCodec != nil {
+		ttlTimer := time.NewTimer(m.defaultTtl)
+		pingChannel := m.Ping()
+		select {
+		case pingResponse := <-pingChannel:
+			if !ttlTimer.Stop() {
+				<-ttlTimer.C
+			}
+			return pingResponse.GetErr() == nil
+		case <-ttlTimer.C:
+			ttlTimer.Stop()
+			m.handleTimeout()
+			return false
+		}
+	}
+	return false
+}
+
+func (m *Connection) Ping() <-chan plc4go.PlcConnectionPingResult {
+	result := make(chan plc4go.PlcConnectionPingResult)
+
+	go func() {
+		// Send the connection state request
+		_, err := m.sendConnectionStateRequest()
+		if err != nil {
+			result <- _default.NewDefaultPlcConnectionPingResult(errors.Wrap(err, "got an error"))
+		} else {
+			result <- _default.NewDefaultPlcConnectionPingResult(nil)
+		}
+		return
+	}()
+
+	return result
+}
+
+func (m *Connection) GetMetadata() apiModel.PlcConnectionMetadata {
+	return m.metadata
+}
+
+func (m *Connection) ReadRequestBuilder() apiModel.PlcReadRequestBuilder {
+	return internalModel.NewDefaultPlcReadRequestBuilder(
+		m.fieldHandler, NewReader(m))
+}
+
+func (m *Connection) WriteRequestBuilder() apiModel.PlcWriteRequestBuilder {
+	return internalModel.NewDefaultPlcWriteRequestBuilder(
+		m.fieldHandler, m.valueHandler, NewWriter(m.messageCodec))
+}
+
+func (m *Connection) SubscriptionRequestBuilder() apiModel.PlcSubscriptionRequestBuilder {
+	return internalModel.NewDefaultPlcSubscriptionRequestBuilder(
+		m.fieldHandler, m.valueHandler, NewSubscriber(m))
+}
+
+func (m *Connection) BrowseRequestBuilder() apiModel.PlcBrowseRequestBuilder {
+	return internalModel.NewDefaultPlcBrowseRequestBuilder(NewBrowser(m, m.messageCodec))
+}
+
+func (m *Connection) UnsubscriptionRequestBuilder() apiModel.PlcUnsubscriptionRequestBuilder {
+	return nil /*internalModel.NewDefaultPlcUnsubscriptionRequestBuilder(
+	  m.fieldHandler, m.valueHandler, NewSubscriber(m.messageCodec))*/
+}
+
+func (m *Connection) GetTransportInstance() transports.TransportInstance {
+	if mc, ok := m.messageCodec.(spi.TransportInstanceExposer); ok {
+		return mc.GetTransportInstance()
+	}
+	return nil
+}
+
+func (m *Connection) GetPlcFieldHandler() spi.PlcFieldHandler {
+	return m.fieldHandler
+}
+
+func (m *Connection) GetPlcValueHandler() spi.PlcValueHandler {
+	return m.valueHandler
+}
diff --git a/plc4go/internal/knxnetip/ConnectionDriverSpecificOperations.go b/plc4go/internal/knxnetip/ConnectionDriverSpecificOperations.go
new file mode 100644
index 0000000000..c464d7e893
--- /dev/null
+++ b/plc4go/internal/knxnetip/ConnectionDriverSpecificOperations.go
@@ -0,0 +1,521 @@
+/*
+ * 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 knxnetip
+
+import (
+	"math"
+	"strconv"
+	"time"
+
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	values2 "github.com/apache/plc4x/plc4go/internal/spi/values"
+	"github.com/apache/plc4x/plc4go/pkg/plc4go/values"
+	driverModel "github.com/apache/plc4x/plc4go/protocols/knxnetip/readwrite/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+)
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+// KNX Specific Operations used by the driver internally
+//
+// These functions all provide access to some of the internal KNX operations
+// They provide this functionality to other parts of the KNX driver, which are
+// not part of the PLC4Go API.
+//
+// Remarks about these functions:
+// They expect the called private functions to handle timeouts, so these will not.
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+func (m *Connection) ReadGroupAddress(groupAddress []byte, datapointType *driverModel.KnxDatapointType) <-chan KnxReadResult {
+	result := make(chan KnxReadResult)
+
+	sendResponse := func(value *values.PlcValue, numItems uint8, err error) {
+		timeout := time.NewTimer(time.Millisecond * 10)
+		select {
+		case result <- KnxReadResult{
+			value:    value,
+			numItems: numItems,
+			err:      err,
+		}:
+			if !timeout.Stop() {
+				<-timeout.C
+			}
+		case <-timeout.C:
+			timeout.Stop()
+		}
+	}
+
+	go func() {
+		groupAddressReadResponse, err := m.sendGroupAddressReadRequest(groupAddress)
+		if err != nil {
+			sendResponse(nil, 0, errors.Wrap(err, "error reading group address"))
+			return
+		}
+
+		var payload []byte
+		// TODO: maybe groupAddressReadResponse.DataFirstByte can be written as uint 6 so the we wouldn't need to cast
+		payload = append(payload, byte(groupAddressReadResponse.DataFirstByte))
+		payload = append(payload, groupAddressReadResponse.Data...)
+
+		// Parse the response data.
+		rb := utils.NewReadBufferByteBased(payload)
+		// If the size of the field is greater than 6, we have to skip the first byte
+		if datapointType.DatapointMainType().SizeInBits() > 6 {
+			_, _ = rb.ReadUint8("datapointType", 8)
+		}
+		// Set a default datatype if none is provided
+		if *datapointType == driverModel.KnxDatapointType_DPT_UNKNOWN {
+			defaultDatapointType := driverModel.KnxDatapointType_USINT
+			datapointType = &defaultDatapointType
+		}
+		// Parse the value
+		plcValue, err := driverModel.KnxDatapointParse(rb, *datapointType)
+		if err != nil {
+			sendResponse(nil, 0, errors.Wrap(err, "error parsing group address response"))
+			return
+		}
+
+		// Return the value
+		sendResponse(&plcValue, 1, nil)
+	}()
+
+	return result
+}
+
+func (m *Connection) DeviceConnect(targetAddress driverModel.KnxAddress) <-chan KnxDeviceConnectResult {
+	result := make(chan KnxDeviceConnectResult)
+
+	sendResponse := func(connection *KnxDeviceConnection, err error) {
+		timeout := time.NewTimer(time.Millisecond * 10)
+		select {
+		case result <- KnxDeviceConnectResult{
+			connection: connection,
+			err:        err,
+		}:
+			if !timeout.Stop() {
+				<-timeout.C
+			}
+		case <-timeout.C:
+			timeout.Stop()
+		}
+	}
+
+	go func() {
+		// If we're already connected, use that connection instead.
+		if connection, ok := m.DeviceConnections[targetAddress]; ok {
+			sendResponse(connection, nil)
+			return
+		}
+
+		// First send a connection request
+		controlConnectResponse, err := m.sendDeviceConnectionRequest(targetAddress)
+		if err != nil {
+			sendResponse(nil, errors.Wrap(err, "error creating device connection"))
+			return
+		}
+		if controlConnectResponse == nil {
+			sendResponse(nil, errors.New("error creating device connection"))
+			return
+		}
+
+		// Create the new connection object.
+		connection := &KnxDeviceConnection{
+			counter: 0,
+			// I was told this value on the knx-forum.
+			// Seems the max payload is 3 bytes less ...
+			maxApdu: 0, // This is the default max APDU Size
+		}
+		m.DeviceConnections[targetAddress] = connection
+
+		// If the connection request was successful, try to read the device-descriptor
+		deviceDescriptorResponse, err := m.sendDeviceDeviceDescriptorReadRequest(targetAddress)
+		if err != nil {
+			sendResponse(nil, errors.New(
+				"error reading device descriptor: "+err.Error()))
+			return
+		}
+		// Save the device-descriptor value
+		deviceDescriptor := uint16(deviceDescriptorResponse.Data[0])<<8 | (uint16(deviceDescriptorResponse.Data[1]) & 0xFF)
+		connection.deviceDescriptor = deviceDescriptor
+
+		// Last, not least, read the max APDU size
+		// If we were able to read the max APDU size, then use the minimum of
+		// the connection APDU size and the device APDU size, otherwise use the
+		// default APDU Size of 15
+		// Defined in: 03_05_01 Resources v01.09.03 AS Page 40
+		deviceApduSize := uint16(15)
+		propertyValueResponse, err := m.sendDevicePropertyReadRequest(targetAddress, 0, 56, 1, 1)
+		if err == nil {
+			// If the count is 0, then this property doesn't exist or the user has no permission to read it.
+			// In all other cases we expect the response to contain the value.
+			if propertyValueResponse.Count > 0 {
+				dataLength := uint8(len(propertyValueResponse.Data))
+				data := propertyValueResponse.Data
+				rb := utils.NewReadBufferByteBased(data)
+				plcValue, err := driverModel.KnxPropertyParse(rb,
+					driverModel.KnxInterfaceObjectProperty_PID_DEVICE_MAX_APDULENGTH.PropertyDataType(), dataLength)
+
+				// Return the result
+				if err == nil {
+					deviceApduSize = plcValue.GetUint16()
+				} else {
+					log.Debug().Err(err).Msgf("Error parsing knx property")
+				}
+			}
+		}
+
+		// Set the max apdu size for this connection.
+		connection.maxApdu = uint16(math.Min(float64(deviceApduSize), 240))
+
+		sendResponse(connection, nil)
+	}()
+
+	return result
+}
+
+func (m *Connection) DeviceDisconnect(targetAddress driverModel.KnxAddress) <-chan KnxDeviceDisconnectResult {
+	result := make(chan KnxDeviceDisconnectResult)
+
+	sendResponse := func(connection *KnxDeviceConnection, err error) {
+		timeout := time.NewTimer(time.Millisecond * 10)
+		select {
+		case result <- KnxDeviceDisconnectResult{
+			connection: connection,
+			err:        err,
+		}:
+			if !timeout.Stop() {
+				<-timeout.C
+			}
+		case <-timeout.C:
+			timeout.Stop()
+		}
+	}
+
+	go func() {
+		if connection, ok := m.DeviceConnections[targetAddress]; ok {
+			_, err := m.sendDeviceDisconnectionRequest(targetAddress)
+
+			// Remove the connection from the list.
+			delete(m.DeviceConnections, targetAddress)
+
+			sendResponse(connection, err)
+		} else {
+			sendResponse(connection, nil)
+		}
+	}()
+
+	return result
+}
+
+func (m *Connection) DeviceAuthenticate(targetAddress driverModel.KnxAddress, buildingKey []byte) <-chan KnxDeviceAuthenticateResult {
+	result := make(chan KnxDeviceAuthenticateResult)
+
+	sendResponse := func(err error) {
+		timeout := time.NewTimer(time.Millisecond * 10)
+		select {
+		case result <- KnxDeviceAuthenticateResult{
+			err: err,
+		}:
+			if !timeout.Stop() {
+				<-timeout.C
+			}
+		case <-timeout.C:
+			timeout.Stop()
+		}
+	}
+
+	go func() {
+		// Check if there is already a connection available,
+		// if not, create a new one.
+		connection, ok := m.DeviceConnections[targetAddress]
+		if !ok {
+			connections := m.DeviceConnect(targetAddress)
+			deviceConnectionResult := <-connections
+			// If we didn't get a connect, abort
+			if deviceConnectionResult.err != nil {
+				sendResponse(errors.Wrapf(deviceConnectionResult.err, "error connecting to device at: %s", KnxAddressToString(&targetAddress)))
+			}
+		}
+
+		// If we successfully got a connection, read the property
+		if connection == nil {
+			sendResponse(errors.New("unable to connect to device"))
+			return
+		}
+		authenticationLevel := uint8(0)
+		authenticationResponse, err := m.sendDeviceAuthentication(targetAddress, authenticationLevel, buildingKey)
+		if err == nil {
+			if authenticationResponse.Level == authenticationLevel {
+				sendResponse(nil)
+			} else {
+				// We authenticated correctly but not to the level requested.
+				sendResponse(errors.Errorf("got error authenticating at device %s",
+					KnxAddressToString(&targetAddress)))
+			}
+		} else {
+			sendResponse(errors.Errorf("got error authenticating at device %s", KnxAddressToString(&targetAddress)))
+		}
+	}()
+
+	return result
+}
+
+func (m *Connection) DeviceReadProperty(targetAddress driverModel.KnxAddress, objectId uint8, propertyId uint8, propertyIndex uint16, numElements uint8) <-chan KnxReadResult {
+	result := make(chan KnxReadResult)
+
+	sendResponse := func(value *values.PlcValue, numItems uint8, err error) {
+		timeout := time.NewTimer(time.Millisecond * 10)
+		select {
+		case result <- KnxReadResult{
+			value:    value,
+			numItems: numItems,
+			err:      err,
+		}:
+			if !timeout.Stop() {
+				<-timeout.C
+			}
+		case <-timeout.C:
+			timeout.Stop()
+		}
+	}
+
+	go func() {
+		// Check if there is already a connection available,
+		// if not, create a new one.
+		connection, ok := m.DeviceConnections[targetAddress]
+		if !ok {
+			connections := m.DeviceConnect(targetAddress)
+			deviceConnectionResult := <-connections
+			// If we didn't get a connect, abort
+			if deviceConnectionResult.err != nil {
+				sendResponse(nil,
+					0,
+					errors.Wrapf(deviceConnectionResult.err, "error connecting to device at: %s", KnxAddressToString(&targetAddress)),
+				)
+			}
+		}
+
+		// If we successfully got a connection, read the property
+		if connection == nil {
+			sendResponse(nil, 0, errors.New("unable to connect to device"))
+			return
+		}
+		propertyValueResponse, err := m.sendDevicePropertyReadRequest(targetAddress, objectId, propertyId, propertyIndex, numElements)
+		if err != nil {
+			sendResponse(nil, 0, err)
+			return
+		}
+
+		// Find out the type of the property
+		var objectType *driverModel.KnxInterfaceObjectType
+		for curObjectType := driverModel.KnxInterfaceObjectType_OT_UNKNOWN; curObjectType <= driverModel.KnxInterfaceObjectType_OT_SUNBLIND_SENSOR_BASIC; curObjectType++ {
+			if curObjectType.Code() == strconv.Itoa(int(objectId)) {
+				objectType = &curObjectType
+				break
+			}
+		}
+		property := driverModel.KnxInterfaceObjectProperty_PID_UNKNOWN
+		if objectType != nil {
+			for curProperty := driverModel.KnxInterfaceObjectProperty_PID_UNKNOWN; curProperty <= driverModel.KnxInterfaceObjectProperty_PID_SUNBLIND_SENSOR_BASIC_ENABLE_TOGGLE_MODE; curProperty++ {
+				if curProperty.PropertyId() == propertyId &&
+					(curProperty.ObjectType() == driverModel.KnxInterfaceObjectType_OT_GENERAL ||
+						curProperty.ObjectType() == *objectType) {
+					property = curProperty
+					break
+				}
+			}
+		}
+
+		dataLength := uint8(len(propertyValueResponse.Data))
+		data := propertyValueResponse.Data
+		rb := utils.NewReadBufferByteBased(data)
+		plcValue, err := driverModel.KnxPropertyParse(rb, property.PropertyDataType(), dataLength)
+		if err != nil {
+			sendResponse(nil, 0, err)
+		} else {
+			sendResponse(&plcValue, 1, err)
+		}
+	}()
+
+	return result
+}
+
+func (m *Connection) DeviceReadPropertyDescriptor(targetAddress driverModel.KnxAddress, objectId uint8, propertyId uint8) <-chan KnxReadResult {
+	result := make(chan KnxReadResult)
+
+	sendResponse := func(value *values.PlcValue, numItems uint8, err error) {
+		timeout := time.NewTimer(time.Millisecond * 10)
+		select {
+		case result <- KnxReadResult{
+			value:    value,
+			numItems: numItems,
+			err:      err,
+		}:
+			if !timeout.Stop() {
+				<-timeout.C
+			}
+		case <-timeout.C:
+			timeout.Stop()
+		}
+	}
+
+	go func() {
+		// Check if there is already a connection available,
+		// if not, create a new one.
+		connection, ok := m.DeviceConnections[targetAddress]
+		if !ok {
+			connections := m.DeviceConnect(targetAddress)
+			deviceConnectionResult := <-connections
+			// If we didn't get a connect, abort
+			if deviceConnectionResult.err != nil {
+				sendResponse(
+					nil,
+					0,
+					errors.Wrapf(deviceConnectionResult.err, "error connecting to device at: %s", KnxAddressToString(&targetAddress)),
+				)
+			}
+		}
+
+		if connection == nil {
+			sendResponse(nil, 0, errors.New("unable to connect to device"))
+			return
+		}
+		// If we successfully got a connection, read the property
+		propertyDescriptionResponse, err := m.sendDevicePropertyDescriptionReadRequest(targetAddress, objectId, propertyId)
+		if err != nil {
+			sendResponse(nil, 0, err)
+			return
+		}
+
+		val := map[string]values.PlcValue{}
+		val["writable"] = values2.NewPlcBOOL(propertyDescriptionResponse.WriteEnabled)
+		val["dataType"] = values2.NewPlcSTRING(propertyDescriptionResponse.PropertyDataType.Name())
+		val["maxElements"] = values2.NewPlcUINT(propertyDescriptionResponse.MaxNrOfElements)
+		val["readLevel"] = values2.NewPlcSTRING(propertyDescriptionResponse.ReadLevel.String())
+		val["writeLevel"] = values2.NewPlcSTRING(propertyDescriptionResponse.WriteLevel.String())
+		str := values2.NewPlcStruct(val)
+		sendResponse(&str, 1, nil)
+	}()
+
+	return result
+}
+
+func (m *Connection) DeviceReadMemory(targetAddress driverModel.KnxAddress, address uint16, numElements uint8, datapointType *driverModel.KnxDatapointType) <-chan KnxReadResult {
+	result := make(chan KnxReadResult)
+
+	sendResponse := func(value *values.PlcValue, numItems uint8, err error) {
+		timeout := time.NewTimer(time.Millisecond * 10)
+		select {
+		case result <- KnxReadResult{
+			value:    value,
+			numItems: numItems,
+			err:      err,
+		}:
+			if !timeout.Stop() {
+				<-timeout.C
+			}
+		case <-timeout.C:
+			timeout.Stop()
+		}
+	}
+
+	go func() {
+		// Set a default datatype, if none is specified
+		if datapointType == nil {
+			dpt := driverModel.KnxDatapointType_USINT
+			datapointType = &dpt
+		}
+
+		// Check if there is already a connection available,
+		// if not, create a new one.
+		connection, ok := m.DeviceConnections[targetAddress]
+		if !ok {
+			connections := m.DeviceConnect(targetAddress)
+			deviceConnectionResult := <-connections
+			// If we didn't get a connect, abort
+			if deviceConnectionResult.err != nil {
+				sendResponse(
+					nil,
+					0,
+					errors.Wrapf(deviceConnectionResult.err, "error connecting to device at: %s", KnxAddressToString(&targetAddress)),
+				)
+			}
+		}
+
+		if connection == nil {
+			// TODO: do we need to send a response here
+			return
+		}
+		// If we successfully got a connection, read the property
+		// Depending on the gateway Max APDU and the device Max APDU, split this up into multiple requests.
+		// An APDU starts with the last 6 bits of the first data byte containing the count
+		// followed by the 16-bit address, so these are already used.
+		elementSize := datapointType.DatapointMainType().SizeInBits() / 8
+		remainingRequestElements := numElements
+		curStartingAddress := address
+		var results []values.PlcValue
+		for remainingRequestElements > 0 {
+			// As the maxApdu can change, we have to do this in the loop.
+			maxNumBytes := uint8(math.Min(float64(connection.maxApdu-3), float64(63)))
+			maxNumElementsPerRequest := uint8(math.Floor(float64(maxNumBytes / elementSize)))
+			numElements := uint8(math.Min(float64(remainingRequestElements), float64(maxNumElementsPerRequest)))
+			numBytes := numElements * uint8(math.Max(float64(1), float64(datapointType.DatapointMainType().SizeInBits()/8)))
+			memoryReadResponse, err := m.sendDeviceMemoryReadRequest(targetAddress, curStartingAddress, numBytes)
+			if err != nil {
+				// TODO: do we need to send a response here
+				return
+			}
+
+			// If the number of bytes read is less than expected,
+			// Update the connection.maxApdu value. This is required
+			// as some devices seem to be sending back less than the
+			// number of bytes specified than the maxApdu.
+			if uint8(len(memoryReadResponse.Data)) < numBytes {
+				connection.maxApdu = uint16(len(memoryReadResponse.Data) + 3)
+			}
+
+			// Parse the data according to the property type information
+			rb := utils.NewReadBufferByteBased(memoryReadResponse.Data)
+			for rb.HasMore(datapointType.DatapointMainType().SizeInBits()) {
+				plcValue, err := driverModel.KnxDatapointParse(rb, *datapointType)
+				// Return the result
+				if err != nil {
+					sendResponse(nil, 0, err)
+					return
+				}
+				results = append(results, plcValue)
+
+				// Update the counters and addresses.
+				remainingRequestElements--
+				curStartingAddress = curStartingAddress + uint16(elementSize)
+			}
+			// If there are still remaining bytes, keep them for the next time.
+		}
+		if len(results) > 1 {
+			var plcList values.PlcValue
+			plcList = values2.NewPlcList(results)
+			sendResponse(&plcList, 1, nil)
+		} else if len(results) == 1 {
+			sendResponse(&results[0], 1, nil)
+		}
+	}()
+
+	return result
+}
diff --git a/plc4go/internal/knxnetip/ConnectionHelper.go b/plc4go/internal/knxnetip/ConnectionHelper.go
new file mode 100644
index 0000000000..69b9f37f46
--- /dev/null
+++ b/plc4go/internal/knxnetip/ConnectionHelper.go
@@ -0,0 +1,237 @@
+/*
+ * 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 knxnetip
+
+import (
+	"fmt"
+	"math"
+	"net"
+	"strconv"
+	"sync/atomic"
+	"time"
+
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	"github.com/apache/plc4x/plc4go/internal/spi/transports/udp"
+	driverModel "github.com/apache/plc4x/plc4go/protocols/knxnetip/readwrite/model"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+)
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+// Internal helper functions
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+func (m *Connection) interceptIncomingMessage(interface{}) {
+	m.resetTimeout()
+	if m.connectionStateTimer != nil {
+		// Reset the timer for sending the ConnectionStateRequest
+		m.connectionStateTimer.Reset(60 * time.Second)
+	}
+}
+
+func (m *Connection) castIpToKnxAddress(ip net.IP) *driverModel.IPAddress {
+	return driverModel.NewIPAddress(ip[len(ip)-4:])
+}
+
+func (m *Connection) handleIncomingTunnelingRequest(tunnelingRequest *driverModel.TunnelingRequest) {
+	go func() {
+		lDataInd := driverModel.CastLDataInd(tunnelingRequest.Cemi.Child)
+		if lDataInd == nil {
+			return
+		}
+		var destinationAddress []byte
+		switch lDataInd.DataFrame.Child.(type) {
+		case *driverModel.LDataExtended:
+			dataFrame := driverModel.CastLDataExtended(lDataInd.DataFrame)
+			destinationAddress = dataFrame.DestinationAddress
+			switch dataFrame.Apdu.Child.(type) {
+			case *driverModel.ApduDataContainer:
+				container := driverModel.CastApduDataContainer(dataFrame.Apdu)
+				switch container.DataApdu.Child.(type) {
+				case *driverModel.ApduDataGroupValueWrite:
+					groupValueWrite := driverModel.CastApduDataGroupValueWrite(container.DataApdu)
+					if destinationAddress == nil {
+						return
+					}
+					var payload []byte
+					payload = append(payload, byte(groupValueWrite.DataFirstByte))
+					payload = append(payload, groupValueWrite.Data...)
+
+					m.handleValueCacheUpdate(destinationAddress, payload)
+				default:
+					if dataFrame.GroupAddress {
+						return
+					}
+					// If this is an individual address and it is targeted at us, we need to ack that.
+					targetAddress := ByteArrayToKnxAddress(dataFrame.DestinationAddress)
+					if *targetAddress == *m.ClientKnxAddress {
+						log.Info().Msg("Acknowleding an unhandled data message.")
+						_ = m.sendDeviceAck(*dataFrame.SourceAddress, dataFrame.Apdu.Counter, func(err error) {})
+					}
+				}
+			case *driverModel.ApduControlContainer:
+				if dataFrame.GroupAddress {
+					return
+				}
+				// If this is an individual address and it is targeted at us, we need to ack that.
+				targetAddress := ByteArrayToKnxAddress(dataFrame.DestinationAddress)
+				if *targetAddress == *m.ClientKnxAddress {
+					log.Info().Msg("Acknowleding an unhandled contol message.")
+					_ = m.sendDeviceAck(*dataFrame.SourceAddress, dataFrame.Apdu.Counter, func(err error) {})
+				}
+			}
+		default:
+			log.Info().Msg("Unknown unhandled message.")
+		}
+	}()
+}
+
+func (m *Connection) handleValueCacheUpdate(destinationAddress []byte, payload []byte) {
+	addressData := uint16(destinationAddress[0])<<8 | (uint16(destinationAddress[1]) & 0xFF)
+
+	m.valueCacheMutex.RLock()
+	val, ok := m.valueCache[addressData]
+	m.valueCacheMutex.RUnlock()
+	changed := false
+	if !ok || !m.sliceEqual(val, payload) {
+		m.valueCacheMutex.Lock()
+		m.valueCache[addressData] = payload
+		m.valueCacheMutex.Unlock()
+		changed = true
+	}
+	if m.subscribers != nil {
+		for _, subscriber := range m.subscribers {
+			subscriber.handleValueChange(destinationAddress, payload, changed)
+		}
+	}
+}
+
+func (m *Connection) handleTimeout() {
+	// If this is the first timeout in a sequence, start the timer.
+	/*	if m.connectionTimeoutTimer == nil {
+		m.connectionTimeoutTimer = time.NewTimer(m.connectionTtl)
+		go func() {
+			<-m.connectionTimeoutTimer.C
+			m.resetConnection()
+		}()
+	}*/
+}
+
+func (m *Connection) resetTimeout() {
+	if m.connectionTimeoutTimer != nil {
+		if !m.connectionTimeoutTimer.Stop() {
+			select {
+			case <-m.connectionTimeoutTimer.C:
+			default:
+			}
+		}
+		m.connectionTimeoutTimer = nil
+	}
+}
+
+func (m *Connection) resetConnection() {
+	log.Warn().Msg("Reset connection")
+}
+
+func (m *Connection) getGroupAddressNumLevels() uint8 {
+	if val, ok := m.options["group-address-num-levels"]; ok {
+		groupAddressNumLevels, err := strconv.ParseUint(val[0], 10, 8)
+		if err == nil {
+			return uint8(groupAddressNumLevels)
+		}
+	}
+	// TODO: document magic number
+	return 3
+}
+
+func (m *Connection) addSubscriber(subscriber *Subscriber) {
+	for _, sub := range m.subscribers {
+		if sub == subscriber {
+			log.Debug().Msgf("Subscriber %v already added", subscriber)
+			return
+		}
+	}
+	m.subscribers = append(m.subscribers, subscriber)
+}
+
+func (m *Connection) removeSubscriber(subscriber *Subscriber) {
+	for i, sub := range m.subscribers {
+		if sub == subscriber {
+			m.subscribers = append(m.subscribers[:i], m.subscribers[i+1:]...)
+		}
+	}
+}
+
+// TODO: we can replace this with reflect.DeepEqual()
+func (m *Connection) sliceEqual(a, b []byte) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	for i, v := range a {
+		if v != b[i] {
+			return false
+		}
+	}
+	return true
+}
+
+func (m *Connection) getLocalAddress() (*net.UDPAddr, error) {
+	transportInstanceExposer, ok := m.messageCodec.(spi.TransportInstanceExposer)
+	if !ok {
+		return nil, errors.New("used transport, is not a TransportInstanceExposer")
+	}
+
+	// Prepare a SearchReq
+	udpTransportInstance, ok := transportInstanceExposer.GetTransportInstance().(*udp.TransportInstance)
+	if !ok {
+		return nil, errors.New("used transport, is not a UdpTransportInstance")
+	}
+
+	return udpTransportInstance.LocalAddress, nil
+}
+
+func (m *Connection) getNewSequenceCounter() uint8 {
+	sequenceCounter := atomic.AddInt32(&m.SequenceCounter, 1)
+	if sequenceCounter >= math.MaxUint8 {
+		atomic.StoreInt32(&m.SequenceCounter, -1)
+		sequenceCounter = -1
+	}
+	return uint8(sequenceCounter)
+}
+
+func (m *Connection) getNextCounter(targetAddress driverModel.KnxAddress) uint8 {
+	m.Lock()
+	defer m.Unlock()
+
+	connection, ok := m.DeviceConnections[targetAddress]
+	if !ok {
+		return 0
+	}
+	counter := connection.counter
+	connection.counter++
+	if connection.counter >= 16 {
+		connection.counter = 0
+	}
+	return counter
+}
+
+func KnxAddressToString(knxAddress *driverModel.KnxAddress) string {
+	return fmt.Sprintf("%d.%d.%d", knxAddress.MainGroup, knxAddress.MiddleGroup, knxAddress.SubGroup)
+}
diff --git a/plc4go/internal/knxnetip/ConnectionInternalOperations.go b/plc4go/internal/knxnetip/ConnectionInternalOperations.go
new file mode 100644
index 0000000000..ba376dc224
--- /dev/null
+++ b/plc4go/internal/knxnetip/ConnectionInternalOperations.go
@@ -0,0 +1,1183 @@
+/*
+ * 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 knxnetip
+
+import (
+	"reflect"
+	"time"
+
+	"github.com/apache/plc4x/plc4go/internal/spi/plcerrors"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	driverModel "github.com/apache/plc4x/plc4go/protocols/knxnetip/readwrite/model"
+	"github.com/pkg/errors"
+)
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+// KnxNetIpConnection internal operations
+//
+// These are used internally by functions of the KnxNetIpConnection.
+//
+// All of the sendXYZ functions take care of sending a request and waiting for the matching
+// response. They don't actually process the data in the response, they just handle receiving
+// it and returning it to the calling function.
+//
+// They all assume the connection is checked and is available.
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+func (m *Connection) sendGatewaySearchRequest() (*driverModel.SearchResponse, error) {
+	localAddress, err := m.getLocalAddress()
+	if err != nil {
+		return nil, errors.Wrap(err, "error getting local address")
+	}
+
+	localAddr := driverModel.NewIPAddress(localAddress.IP)
+	discoveryEndpoint := driverModel.NewHPAIDiscoveryEndpoint(
+		driverModel.HostProtocolCode_IPV4_UDP, localAddr, uint16(localAddress.Port),
+	)
+	searchRequest := driverModel.NewSearchRequest(discoveryEndpoint)
+
+	result := make(chan *driverModel.SearchResponse)
+	errorResult := make(chan error)
+	err = m.messageCodec.SendRequest(searchRequest,
+		func(message interface{}) bool {
+			searchResponse := driverModel.CastSearchResponse(message)
+			return searchResponse != nil
+		},
+		func(message interface{}) error {
+			searchResponse := driverModel.CastSearchResponse(message)
+			result <- searchResponse
+			return nil
+		},
+		func(err error) error {
+			// If this is a timeout, do a check if the connection requires a reconnection
+			if _, isTimeout := err.(plcerrors.TimeoutError); isTimeout {
+				m.handleTimeout()
+			}
+			errorResult <- errors.Wrap(err, "got error processing request")
+			return nil
+		},
+		m.defaultTtl)
+
+	if err != nil {
+		return nil, errors.Wrap(err, "got error sending search request")
+	}
+
+	ttlTimer := time.NewTimer(m.defaultTtl)
+	select {
+	case response := <-result:
+		if !ttlTimer.Stop() {
+			<-ttlTimer.C
+		}
+		return response, nil
+	case errorResponse := <-errorResult:
+		if !ttlTimer.Stop() {
+			<-ttlTimer.C
+		}
+		return nil, errorResponse
+		// For search requests there is no timeout handler running, so we have to do it manually.
+	case <-ttlTimer.C:
+		ttlTimer.Stop()
+		return nil, errors.New("timeout")
+	}
+}
+
+func (m *Connection) sendGatewayConnectionRequest() (*driverModel.ConnectionResponse, error) {
+	localAddress, err := m.getLocalAddress()
+	if err != nil {
+		return nil, errors.Wrap(err, "error getting local address")
+	}
+
+	localAddr := driverModel.NewIPAddress(localAddress.IP[len(localAddress.IP)-4:])
+	connectionRequest := driverModel.NewConnectionRequest(
+		driverModel.NewHPAIDiscoveryEndpoint(driverModel.HostProtocolCode_IPV4_UDP, localAddr, uint16(localAddress.Port)),
+		driverModel.NewHPAIDataEndpoint(driverModel.HostProtocolCode_IPV4_UDP, localAddr, uint16(localAddress.Port)),
+		driverModel.NewConnectionRequestInformationTunnelConnection(driverModel.KnxLayer_TUNNEL_LINK_LAYER).GetParent(),
+	)
+
+	result := make(chan *driverModel.ConnectionResponse)
+	errorResult := make(chan error)
+	err = m.messageCodec.SendRequest(connectionRequest,
+		func(message interface{}) bool {
+			connectionResponse := driverModel.CastConnectionResponse(message)
+			return connectionResponse != nil
+		},
+		func(message interface{}) error {
+			connectionResponse := driverModel.CastConnectionResponse(message)
+			result <- connectionResponse
+			return nil
+		},
+		func(err error) error {
+			// If this is a timeout, do a check if the connection requires a reconnection
+			if _, isTimeout := err.(plcerrors.TimeoutError); isTimeout {
+				m.handleTimeout()
+			}
+			errorResult <- errors.Wrap(err, "got error processing request")
+			return nil
+		},
+		m.defaultTtl)
+
+	if err != nil {
+		return nil, errors.Wrap(err, "got error sending request")
+	}
+
+	select {
+	case response := <-result:
+		return response, nil
+	case errorResponse := <-errorResult:
+		return nil, errorResponse
+	}
+}
+
+func (m *Connection) sendGatewayDisconnectionRequest() (*driverModel.DisconnectResponse, error) {
+	localAddress, err := m.getLocalAddress()
+	if err != nil {
+		return nil, errors.Wrap(err, "error getting local address")
+	}
+
+	localAddr := driverModel.NewIPAddress(localAddress.IP[len(localAddress.IP)-4:])
+	disconnectRequest := driverModel.NewDisconnectRequest(
+		m.CommunicationChannelId,
+		driverModel.NewHPAIControlEndpoint(
+			driverModel.HostProtocolCode_IPV4_UDP,
+			localAddr,
+			uint16(localAddress.Port),
+		),
+	)
+
+	result := make(chan *driverModel.DisconnectResponse)
+	errorResult := make(chan error)
+	err = m.messageCodec.SendRequest(disconnectRequest,
+		func(message interface{}) bool {
+			disconnectResponse := driverModel.CastDisconnectResponse(message)
+			return disconnectResponse != nil
+		},
+		func(message interface{}) error {
+			disconnectResponse := driverModel.CastDisconnectResponse(message)
+			result <- disconnectResponse
+			return nil
+		},
+		func(err error) error {
+			// If this is a timeout, do a check if the connection requires a reconnection
+			if _, isTimeout := err.(plcerrors.TimeoutError); isTimeout {
+				m.handleTimeout()
+			}
+			errorResult <- errors.Wrap(err, "got error processing request")
+			return nil
+		},
+		m.defaultTtl)
+
+	if err != nil {
+		return nil, errors.Wrap(err, "got error sending request")
+	}
+
+	select {
+	case response := <-result:
+		return response, nil
+	case errorResponse := <-errorResult:
+		return nil, errorResponse
+	}
+}
+
+func (m *Connection) sendConnectionStateRequest() (*driverModel.ConnectionStateResponse, error) {
+	localAddress, err := m.getLocalAddress()
+	if err != nil {
+		return nil, errors.Wrap(err, "error getting local address")
+	}
+
+	localAddr := driverModel.NewIPAddress(localAddress.IP[len(localAddress.IP)-4:])
+	connectionStateRequest := driverModel.NewConnectionStateRequest(
+		m.CommunicationChannelId,
+		driverModel.NewHPAIControlEndpoint(
+			driverModel.HostProtocolCode_IPV4_UDP,
+			localAddr, uint16(localAddress.Port)))
+
+	result := make(chan *driverModel.ConnectionStateResponse)
+	errorResult := make(chan error)
+	err = m.messageCodec.SendRequest(connectionStateRequest,
+		func(message interface{}) bool {
+			connectionStateResponse := driverModel.CastConnectionStateResponse(message)
+			return connectionStateResponse != nil
+		},
+		func(message interface{}) error {
+			connectionStateResponse := driverModel.CastConnectionStateResponse(message)
+			result <- connectionStateResponse
+			return nil
+		},
+		func(err error) error {
+			// If this is a timeout, do a check if the connection requires a reconnection
+			if _, isTimeout := err.(plcerrors.TimeoutError); isTimeout {
+				m.handleTimeout()
+			}
+			errorResult <- errors.Wrap(err, "got error processing request")
+			return nil
+		},
+		m.defaultTtl)
+
+	if err != nil {
+		return nil, errors.Wrap(err, "got error sending request")
+	}
+
+	select {
+	case response := <-result:
+		return response, nil
+	case errorResponse := <-errorResult:
+		return nil, errorResponse
+	}
+}
+
+func (m *Connection) sendGroupAddressReadRequest(groupAddress []byte) (*driverModel.ApduDataGroupValueResponse, error) {
+	// Send the property read request and wait for a confirmation that this property is readable.
+	groupAddressReadRequest := driverModel.NewTunnelingRequest(
+		driverModel.NewTunnelingRequestDataBlock(m.CommunicationChannelId, m.getNewSequenceCounter()),
+		driverModel.NewLDataReq(
+			0,
+			nil,
+			driverModel.NewLDataExtended(
+				true,
+				6,
+				0,
+				m.ClientKnxAddress, groupAddress,
+				driverModel.NewApduDataContainer(driverModel.NewApduDataGroupValueRead(0).GetParent(), false, 0, 0).GetParent(),
+				true,
+				true,
+				driverModel.CEMIPriority_LOW,
+				false,
+				false,
+			).GetParent(),
+			0,
+		).GetParent(),
+		0,
+	)
+
+	result := make(chan *driverModel.ApduDataGroupValueResponse)
+	errorResult := make(chan error)
+	err := m.messageCodec.SendRequest(
+		groupAddressReadRequest,
+		func(message interface{}) bool {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			if tunnelingRequest == nil ||
+				tunnelingRequest.TunnelingRequestDataBlock.CommunicationChannelId != m.CommunicationChannelId {
+				return false
+			}
+			lDataInd := driverModel.CastLDataInd(tunnelingRequest.Cemi)
+			if lDataInd == nil {
+				return false
+			}
+			dataFrameExt := driverModel.CastLDataExtended(lDataInd.DataFrame)
+			if dataFrameExt == nil {
+				return false
+			}
+			dataContainer := driverModel.CastApduDataContainer(dataFrameExt.Apdu)
+			if dataContainer == nil {
+				return false
+			}
+			groupReadResponse := driverModel.CastApduDataGroupValueResponse(dataContainer.DataApdu)
+			if groupReadResponse == nil {
+				return false
+			}
+			// Check if it's a value response for the given group address
+			return dataFrameExt.GroupAddress && reflect.DeepEqual(dataFrameExt.DestinationAddress, groupAddress)
+		},
+		func(message interface{}) error {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			lDataInd := driverModel.CastLDataInd(tunnelingRequest.Cemi)
+			dataFrameExt := driverModel.CastLDataExtended(lDataInd.DataFrame)
+			dataContainer := driverModel.CastApduDataContainer(dataFrameExt.Apdu)
+			groupReadResponse := driverModel.CastApduDataGroupValueResponse(dataContainer.DataApdu)
+
+			result <- groupReadResponse
+			return nil
+		},
+		func(err error) error {
+			// If this is a timeout, do a check if the connection requires a reconnection
+			if _, isTimeout := err.(plcerrors.TimeoutError); isTimeout {
+				m.handleTimeout()
+			}
+			errorResult <- errors.Wrap(err, "got error processing request")
+			return nil
+		},
+		m.defaultTtl)
+
+	if err != nil {
+		return nil, errors.Wrap(err, "got error sending request")
+	}
+
+	select {
+	case response := <-result:
+		return response, nil
+	case errorResponse := <-errorResult:
+		return nil, errorResponse
+	}
+}
+
+func (m *Connection) sendDeviceConnectionRequest(targetAddress driverModel.KnxAddress) (*driverModel.ApduControlConnect, error) {
+	// Send a connection request to the individual KNX device
+	deviceConnectionRequest := driverModel.NewTunnelingRequest(
+		driverModel.NewTunnelingRequestDataBlock(m.CommunicationChannelId, m.getNewSequenceCounter()),
+		driverModel.NewLDataReq(
+			0,
+			nil,
+			driverModel.NewLDataExtended(
+				false,
+				6,
+				uint8(0),
+				driverModel.NewKnxAddress(0, 0, 0), KnxAddressToByteArray(targetAddress),
+				driverModel.NewApduControlContainer(driverModel.NewApduControlConnect().GetParent(), false, 0, 0).GetParent(),
+				true,
+				true,
+				driverModel.CEMIPriority_SYSTEM,
+				false,
+				false,
+			).GetParent(),
+			0,
+		).GetParent(),
+		0,
+	)
+
+	result := make(chan *driverModel.ApduControlConnect)
+	errorResult := make(chan error)
+	err := m.messageCodec.SendRequest(
+		deviceConnectionRequest,
+		// The Gateway is now supposed to send an Ack to this request.
+		func(message interface{}) bool {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			if tunnelingRequest == nil ||
+				tunnelingRequest.TunnelingRequestDataBlock.CommunicationChannelId != m.CommunicationChannelId {
+				return false
+			}
+			lDataCon := driverModel.CastLDataCon(tunnelingRequest.Cemi)
+			if lDataCon == nil {
+				return false
+			}
+			lDataFrameExt := driverModel.CastLDataExtended(lDataCon.DataFrame)
+			if lDataFrameExt == nil {
+				return false
+			}
+			// Check if the address matches
+			if *ByteArrayToKnxAddress(lDataFrameExt.DestinationAddress) != targetAddress {
+				return false
+			}
+			apduControlContainer := driverModel.CastApduControlContainer(lDataFrameExt.Apdu)
+			if apduControlContainer == nil {
+				return false
+			}
+			apduControlConnect := driverModel.CastApduControlConnect(apduControlContainer.ControlApdu)
+			return apduControlConnect != nil
+		},
+		func(message interface{}) error {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			lDataCon := driverModel.CastLDataCon(tunnelingRequest.Cemi)
+			lDataFrameExt := driverModel.CastLDataExtended(lDataCon.DataFrame)
+			apduControlContainer := driverModel.CastApduControlContainer(lDataFrameExt.Apdu)
+			apduControlConnect := driverModel.CastApduControlConnect(apduControlContainer.ControlApdu)
+
+			// If the error flag is set, there was an error connecting
+			if lDataCon.DataFrame.ErrorFlag {
+				errorResult <- errors.Errorf("error connecting to device at: %s", KnxAddressToString(&targetAddress))
+			} else {
+				result <- apduControlConnect
+			}
+
+			return nil
+		},
+		func(err error) error {
+			// If this is a timeout, do a check if the connection requires a reconnection
+			if _, isTimeout := err.(plcerrors.TimeoutError); isTimeout {
+				m.handleTimeout()
+			}
+			errorResult <- errors.Wrap(err, "got error processing request")
+			return nil
+		},
+		m.defaultTtl)
+
+	if err != nil {
+		return nil, errors.Wrap(err, "got error sending request")
+	}
+
+	select {
+	case response := <-result:
+		return response, nil
+	case errorResponse := <-errorResult:
+		return nil, errorResponse
+	}
+}
+
+func (m *Connection) sendDeviceDisconnectionRequest(targetAddress driverModel.KnxAddress) (*driverModel.ApduControlDisconnect, error) {
+	// Send a connection request to the individual KNX device
+	deviceDisconnectionRequest := driverModel.NewTunnelingRequest(
+		driverModel.NewTunnelingRequestDataBlock(m.CommunicationChannelId, m.getNewSequenceCounter()),
+		driverModel.NewLDataReq(
+			0,
+			nil,
+			driverModel.NewLDataExtended(
+				false,
+				6,
+				uint8(0),
+				driverModel.NewKnxAddress(0, 0, 0), KnxAddressToByteArray(targetAddress),
+				driverModel.NewApduControlContainer(driverModel.NewApduControlDisconnect().GetParent(), false, 0, 0).GetParent(),
+				true,
+				true,
+				driverModel.CEMIPriority_SYSTEM,
+				false,
+				false,
+			).GetParent(),
+			0,
+		).GetParent(),
+		0,
+	)
+
+	result := make(chan *driverModel.ApduControlDisconnect)
+	errorResult := make(chan error)
+	err := m.messageCodec.SendRequest(
+		deviceDisconnectionRequest,
+		// The Gateway is now supposed to send an Ack to this request.
+		func(message interface{}) bool {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			if tunnelingRequest == nil ||
+				tunnelingRequest.TunnelingRequestDataBlock.CommunicationChannelId != m.CommunicationChannelId {
+				return false
+			}
+			lDataCon := driverModel.CastLDataCon(tunnelingRequest.Cemi)
+			if lDataCon == nil {
+				return false
+			}
+			dataFrameExt := driverModel.CastLDataExtended(lDataCon.DataFrame)
+			if dataFrameExt == nil {
+				return false
+			}
+			curTargetAddress := ByteArrayToKnxAddress(dataFrameExt.DestinationAddress)
+			// Check if the address matches
+			if *curTargetAddress != targetAddress {
+				return false
+			}
+			apduControlContainer := driverModel.CastApduControlContainer(dataFrameExt.Apdu)
+			if apduControlContainer == nil {
+				return false
+			}
+			apduControlDisconnect := driverModel.CastApduControlDisconnect(apduControlContainer.ControlApdu)
+			return apduControlDisconnect != nil
+		},
+		func(message interface{}) error {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			lDataCon := driverModel.CastLDataCon(tunnelingRequest.Cemi)
+			dataFrameExt := driverModel.CastLDataExtended(lDataCon.DataFrame)
+			apduControlContainer := driverModel.CastApduControlContainer(dataFrameExt.Apdu)
+			apduControlDisconnect := driverModel.CastApduControlDisconnect(apduControlContainer.ControlApdu)
+
+			// If the error flag is set, there was an error disconnecting
+			if lDataCon.DataFrame.ErrorFlag {
+				errorResult <- errors.Errorf("error disconnecting from device at: %s", KnxAddressToString(&targetAddress))
+			} else {
+				result <- apduControlDisconnect
+			}
+
+			return nil
+		},
+		func(err error) error {
+			// If this is a timeout, do a check if the connection requires a reconnection
+			if _, isTimeout := err.(plcerrors.TimeoutError); isTimeout {
+				m.handleTimeout()
+			}
+			errorResult <- errors.Wrap(err, "got error processing request")
+			return nil
+		},
+		m.defaultTtl)
+
+	if err != nil {
+		return nil, errors.Wrap(err, "got error sending request")
+	}
+
+	select {
+	case response := <-result:
+		return response, nil
+	case errorResponse := <-errorResult:
+		return nil, errorResponse
+	}
+}
+
+func (m *Connection) sendDeviceAuthentication(targetAddress driverModel.KnxAddress, authenticationLevel uint8, buildingKey []byte) (*driverModel.ApduDataExtAuthorizeResponse, error) {
+	// Check if there is already a connection available,
+	// if not, create a new one.
+	connection, ok := m.DeviceConnections[targetAddress]
+	if !ok {
+		return nil, errors.New("not connected")
+	}
+
+	// Send a connection request to the individual KNX device
+	counter := connection.counter
+	connection.counter++
+	deviceAuthenticationRequest := driverModel.NewTunnelingRequest(
+		driverModel.NewTunnelingRequestDataBlock(m.CommunicationChannelId, m.getNewSequenceCounter()),
+		driverModel.NewLDataReq(
+			0,
+			nil,
+			driverModel.NewLDataExtended(
+				false,
+				6,
+				uint8(0),
+				driverModel.NewKnxAddress(0, 0, 0), KnxAddressToByteArray(targetAddress),
+				driverModel.NewApduDataContainer(
+					driverModel.NewApduDataOther(
+						driverModel.NewApduDataExtAuthorizeRequest(authenticationLevel, utils.ByteArrayToUint8Array(buildingKey), 0).GetParent(),
+						0,
+					).GetParent(),
+					true,
+					counter,
+					0,
+				).GetParent(),
+				true,
+				true,
+				driverModel.CEMIPriority_SYSTEM,
+				false,
+				false,
+			).GetParent(),
+			0,
+		).GetParent(),
+		0,
+	)
+
+	result := make(chan *driverModel.ApduDataExtAuthorizeResponse)
+	errorResult := make(chan error)
+	err := m.messageCodec.SendRequest(
+		deviceAuthenticationRequest,
+		// The Gateway is now supposed to send an Ack to this request.
+		func(message interface{}) bool {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			if tunnelingRequest == nil ||
+				tunnelingRequest.TunnelingRequestDataBlock.CommunicationChannelId != m.CommunicationChannelId {
+				return false
+			}
+			lDataInd := driverModel.CastLDataInd(tunnelingRequest.Cemi)
+			if lDataInd == nil {
+				return false
+			}
+			dataFrameExt := driverModel.CastLDataExtended(lDataInd.DataFrame)
+			if dataFrameExt == nil {
+				return false
+			}
+			apduDataContainer := driverModel.CastApduDataContainer(dataFrameExt.Apdu)
+			if apduDataContainer == nil {
+				return false
+			}
+			apduDataOther := driverModel.CastApduDataOther(apduDataContainer.DataApdu)
+			if apduDataOther == nil {
+				return false
+			}
+			apduAuthorizeResponse := driverModel.CastApduDataExtAuthorizeResponse(apduDataOther.ExtendedApdu)
+			if apduAuthorizeResponse == nil {
+				return false
+			}
+			curTargetAddress := ByteArrayToKnxAddress(dataFrameExt.DestinationAddress)
+			// Check if the addresses match
+			if *curTargetAddress != *m.ClientKnxAddress {
+				return false
+			}
+			if *dataFrameExt.SourceAddress != targetAddress {
+				return false
+			}
+			// Check if the counter matches
+			if dataFrameExt.Apdu.Counter != counter {
+				return false
+			}
+			return true
+		},
+		func(message interface{}) error {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			lDataInd := driverModel.CastLDataInd(tunnelingRequest.Cemi)
+			dataFrameExt := driverModel.CastLDataExtended(lDataInd.DataFrame)
+			apduDataContainer := driverModel.CastApduDataContainer(dataFrameExt.Apdu)
+			apduDataOther := driverModel.CastApduDataOther(apduDataContainer.DataApdu)
+			apduAuthorizeResponse := driverModel.CastApduDataExtAuthorizeResponse(apduDataOther.ExtendedApdu)
+
+			// Acknowledge the receipt
+			_ = m.sendDeviceAck(targetAddress, dataFrameExt.Apdu.Counter, func(err error) {
+				// If the error flag is set, there was an error authenticating
+				if lDataInd.DataFrame.ErrorFlag {
+					errorResult <- errors.New("error authenticating at device: " + KnxAddressToString(&targetAddress))
+				} else if err != nil {
+					errorResult <- errors.Wrapf(err, "error sending ack to device: %s", KnxAddressToString(&targetAddress))
+				} else {
+					result <- apduAuthorizeResponse
+				}
+			})
+
+			return nil
+		},
+		func(err error) error {
+			// If this is a timeout, do a check if the connection requires a reconnection
+			if _, isTimeout := err.(plcerrors.TimeoutError); isTimeout {
+				m.handleTimeout()
+			}
+			errorResult <- errors.Wrap(err, "got error processing request")
+			return nil
+		},
+		m.defaultTtl)
+
+	if err != nil {
+		return nil, errors.Wrap(err, "got error sending request")
+	}
+
+	select {
+	case response := <-result:
+		return response, nil
+	case errorResponse := <-errorResult:
+		return nil, errorResponse
+	}
+}
+
+func (m *Connection) sendDeviceDeviceDescriptorReadRequest(targetAddress driverModel.KnxAddress) (*driverModel.ApduDataDeviceDescriptorResponse, error) {
+	// Next, read the device descriptor so we know how we have to communicate with the device.
+	counter := m.getNextCounter(targetAddress)
+	deviceDescriptorReadRequest := driverModel.NewTunnelingRequest(
+		driverModel.NewTunnelingRequestDataBlock(m.CommunicationChannelId, m.getNewSequenceCounter()),
+		driverModel.NewLDataReq(
+			0,
+			nil,
+			driverModel.NewLDataExtended(
+				false,
+				6,
+				uint8(0),
+				driverModel.NewKnxAddress(0, 0, 0),
+				KnxAddressToByteArray(targetAddress),
+				driverModel.NewApduDataContainer(
+					driverModel.NewApduDataDeviceDescriptorRead(0, 0).GetParent(), true, counter, 0,
+				).GetParent(),
+				true,
+				true,
+				driverModel.CEMIPriority_LOW,
+				false,
+				false,
+			).GetParent(),
+			0,
+		).GetParent(),
+		0,
+	)
+
+	result := make(chan *driverModel.ApduDataDeviceDescriptorResponse)
+	errorResult := make(chan error)
+	err := m.messageCodec.SendRequest(
+		deviceDescriptorReadRequest,
+		func(message interface{}) bool {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			if tunnelingRequest == nil ||
+				tunnelingRequest.TunnelingRequestDataBlock.CommunicationChannelId != m.CommunicationChannelId {
+				return false
+			}
+			lDataInd := driverModel.CastLDataInd(tunnelingRequest.Cemi)
+			if lDataInd == nil {
+				return false
+			}
+			dataFrameExt := driverModel.CastLDataExtended(lDataInd.DataFrame)
+			if dataFrameExt == nil {
+				return false
+			}
+			// Check if the address matches
+			if *dataFrameExt.SourceAddress != targetAddress {
+				return false
+			}
+			// Check if the counter matches
+			if dataFrameExt.Apdu.Counter != counter {
+				return false
+			}
+			dataContainer := driverModel.CastApduDataContainer(dataFrameExt.Apdu)
+			if dataContainer == nil {
+				return false
+			}
+			deviceDescriptorResponse := driverModel.CastApduDataDeviceDescriptorResponse(dataContainer.DataApdu)
+			if deviceDescriptorResponse == nil {
+				return false
+			}
+			return true
+		},
+		func(message interface{}) error {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			lDataInd := driverModel.CastLDataInd(tunnelingRequest.Cemi)
+			dataFrame := driverModel.CastLDataExtended(lDataInd.DataFrame)
+			dataContainer := driverModel.CastApduDataContainer(dataFrame.Apdu)
+			deviceDescriptorResponse := driverModel.CastApduDataDeviceDescriptorResponse(dataContainer.DataApdu)
+
+			// Acknowledge the receipt
+			_ = m.sendDeviceAck(targetAddress, dataFrame.Apdu.Counter, func(err error) {
+				// If the error flag is set, there was an error authenticating
+				if lDataInd.DataFrame.ErrorFlag {
+					errorResult <- errors.New("error reading device descriptor from device: " + KnxAddressToString(&targetAddress))
+				} else if err != nil {
+					errorResult <- errors.Wrapf(err, "error sending ack to device: %s", KnxAddressToString(&targetAddress))
+				} else {
+					result <- deviceDescriptorResponse
+				}
+			})
+
+			return nil
+		},
+		func(err error) error {
+			// If this is a timeout, do a check if the connection requires a reconnection
+			if _, isTimeout := err.(plcerrors.TimeoutError); isTimeout {
+				m.handleTimeout()
+			}
+			errorResult <- errors.Wrap(err, "got error processing request")
+			return nil
+		},
+		m.defaultTtl)
+
+	if err != nil {
+		return nil, errors.Wrap(err, "got error sending device descriptor read request")
+	}
+
+	select {
+	case response := <-result:
+		return response, nil
+	case errorResponse := <-errorResult:
+		return nil, errorResponse
+	}
+}
+
+func (m *Connection) sendDevicePropertyReadRequest(targetAddress driverModel.KnxAddress, objectId uint8, propertyId uint8, propertyIndex uint16, numElements uint8) (*driverModel.ApduDataExtPropertyValueResponse, error) {
+	// Next, read the device descriptor so we know how we have to communicate with the device.
+	// Send the property read request and wait for a confirmation that this property is readable.
+	counter := m.getNextCounter(targetAddress)
+	propertyReadRequest := driverModel.NewTunnelingRequest(
+		driverModel.NewTunnelingRequestDataBlock(m.CommunicationChannelId, m.getNewSequenceCounter()),
+		driverModel.NewLDataReq(
+			0,
+			nil,
+			driverModel.NewLDataExtended(
+				false,
+				6,
+				0,
+				driverModel.NewKnxAddress(0, 0, 0),
+				KnxAddressToByteArray(targetAddress),
+				driverModel.NewApduDataContainer(
+					driverModel.NewApduDataOther(
+						driverModel.NewApduDataExtPropertyValueRead(objectId, propertyId, numElements, propertyIndex, 0).GetParent(),
+						0,
+					).GetParent(),
+					true,
+					counter,
+					0,
+				).GetParent(),
+				true,
+				true,
+				driverModel.CEMIPriority_LOW,
+				false,
+				false,
+			).GetParent(),
+			0,
+		).GetParent(),
+		0,
+	)
+
+	result := make(chan *driverModel.ApduDataExtPropertyValueResponse)
+	errorResult := make(chan error)
+	err := m.messageCodec.SendRequest(
+		propertyReadRequest,
+		func(message interface{}) bool {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			if tunnelingRequest == nil ||
+				tunnelingRequest.TunnelingRequestDataBlock.CommunicationChannelId != m.CommunicationChannelId {
+				return false
+			}
+			lDataInd := driverModel.CastLDataInd(tunnelingRequest.Cemi)
+			if lDataInd == nil {
+				return false
+			}
+			dataFrameExt := driverModel.CastLDataExtended(lDataInd.DataFrame)
+			if dataFrameExt == nil {
+				return false
+			}
+			// Check if the address matches
+			if *dataFrameExt.SourceAddress != targetAddress {
+				return false
+			}
+			// Check if the counter matches
+			if dataFrameExt.Apdu.Counter != counter {
+				return false
+			}
+			dataContainer := driverModel.CastApduDataContainer(dataFrameExt.Apdu)
+			if dataContainer == nil {
+				return false
+			}
+			dataApduOther := driverModel.CastApduDataOther(dataContainer.DataApdu)
+			if dataApduOther == nil {
+				return false
+			}
+			propertyValueResponse := driverModel.CastApduDataExtPropertyValueResponse(dataApduOther.ExtendedApdu)
+			if propertyValueResponse == nil {
+				return false
+			}
+			return propertyValueResponse.ObjectIndex == objectId && propertyValueResponse.PropertyId == propertyId
+		},
+		func(message interface{}) error {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			lDataInd := driverModel.CastLDataInd(tunnelingRequest.Cemi)
+			dataFrameExt := driverModel.CastLDataExtended(lDataInd.DataFrame)
+			dataContainer := driverModel.CastApduDataContainer(dataFrameExt.Apdu)
+			dataApduOther := driverModel.CastApduDataOther(dataContainer.DataApdu)
+			propertyValueResponse := driverModel.CastApduDataExtPropertyValueResponse(dataApduOther.ExtendedApdu)
+
+			// Acknowledge the receipt
+			_ = m.sendDeviceAck(targetAddress, dataFrameExt.Apdu.Counter, func(err error) {
+				// If the error flag is set, there was an error authenticating
+				if lDataInd.DataFrame.ErrorFlag {
+					errorResult <- errors.New("error reading property value from device: " + KnxAddressToString(&targetAddress))
+				} else if err != nil {
+					errorResult <- errors.Wrapf(err, "error sending ack to device: %s", KnxAddressToString(&targetAddress))
+				} else {
+					result <- propertyValueResponse
+				}
+			})
+
+			return nil
+		},
+		func(err error) error {
+			// If this is a timeout, do a check if the connection requires a reconnection
+			if _, isTimeout := err.(plcerrors.TimeoutError); isTimeout {
+				m.handleTimeout()
+			}
+			errorResult <- errors.Wrap(err, "got error processing request")
+			return nil
+		},
+		m.defaultTtl)
+
+	if err != nil {
+		return nil, errors.Wrap(err, "got error sending device property read request")
+	}
+
+	select {
+	case response := <-result:
+		return response, nil
+	case errorResponse := <-errorResult:
+		return nil, errorResponse
+	}
+}
+
+func (m *Connection) sendDevicePropertyDescriptionReadRequest(targetAddress driverModel.KnxAddress, objectId uint8, propertyId uint8) (*driverModel.ApduDataExtPropertyDescriptionResponse, error) {
+	// Next, read the device descriptor so we know how we have to communicate with the device.
+	// Send the property read request and wait for a confirmation that this property is readable.
+	counter := m.getNextCounter(targetAddress)
+	propertyReadRequest := driverModel.NewTunnelingRequest(
+		driverModel.NewTunnelingRequestDataBlock(m.CommunicationChannelId, m.getNewSequenceCounter()),
+		driverModel.NewLDataReq(
+			0,
+			nil,
+			driverModel.NewLDataExtended(
+				false,
+				6,
+				0,
+				driverModel.NewKnxAddress(0, 0, 0),
+				KnxAddressToByteArray(targetAddress),
+				driverModel.NewApduDataContainer(
+					driverModel.NewApduDataOther(
+						driverModel.NewApduDataExtPropertyDescriptionRead(objectId, propertyId, 1, 0).GetParent(),
+						0,
+					).GetParent(),
+					true,
+					counter,
+					0,
+				).GetParent(),
+				true,
+				true,
+				driverModel.CEMIPriority_LOW,
+				false,
+				false,
+			).GetParent(),
+			0,
+		).GetParent(),
+		0,
+	)
+
+	result := make(chan *driverModel.ApduDataExtPropertyDescriptionResponse)
+	errorResult := make(chan error)
+	err := m.messageCodec.SendRequest(
+		propertyReadRequest,
+		func(message interface{}) bool {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			if tunnelingRequest == nil ||
+				tunnelingRequest.TunnelingRequestDataBlock.CommunicationChannelId != m.CommunicationChannelId {
+				return false
+			}
+			lDataInd := driverModel.CastLDataInd(tunnelingRequest.Cemi)
+			if lDataInd == nil {
+				return false
+			}
+			dataFrameExt := driverModel.CastLDataExtended(lDataInd.DataFrame)
+			if dataFrameExt == nil {
+				return false
+			}
+			// Check if the address matches
+			if *dataFrameExt.SourceAddress != targetAddress {
+				return false
+			}
+			// Check if the counter matches
+			if dataFrameExt.Apdu.Counter != counter {
+				return false
+			}
+			dataContainer := driverModel.CastApduDataContainer(dataFrameExt.Apdu)
+			if dataContainer == nil {
+				return false
+			}
+			dataApduOther := driverModel.CastApduDataOther(dataContainer.DataApdu)
+			if dataApduOther == nil {
+				return false
+			}
+			propertyDescriptionResponse := driverModel.CastApduDataExtPropertyDescriptionResponse(dataApduOther.ExtendedApdu)
+			if propertyDescriptionResponse == nil {
+				return false
+			}
+			return propertyDescriptionResponse.ObjectIndex == objectId && propertyDescriptionResponse.PropertyId == propertyId
+		},
+		func(message interface{}) error {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			lDataInd := driverModel.CastLDataInd(tunnelingRequest.Cemi)
+			dataFrameExt := driverModel.CastLDataExtended(lDataInd.DataFrame)
+			dataContainer := driverModel.CastApduDataContainer(dataFrameExt.Apdu)
+			dataApduOther := driverModel.CastApduDataOther(dataContainer.DataApdu)
+			propertyDescriptionResponse := driverModel.CastApduDataExtPropertyDescriptionResponse(dataApduOther.ExtendedApdu)
+
+			// Acknowledge the receipt
+			_ = m.sendDeviceAck(targetAddress, dataFrameExt.Apdu.Counter, func(err error) {
+				// If the error flag is set, there was an error authenticating
+				if lDataInd.DataFrame.ErrorFlag {
+					errorResult <- errors.Errorf("error reading property description from device: %s", KnxAddressToString(&targetAddress))
+				} else if err != nil {
+					errorResult <- errors.Wrapf(err, "error sending ack to device: %s", KnxAddressToString(&targetAddress))
+				} else {
+					result <- propertyDescriptionResponse
+				}
+			})
+
+			return nil
+		},
+		func(err error) error {
+			// If this is a timeout, do a check if the connection requires a reconnection
+			if _, isTimeout := err.(plcerrors.TimeoutError); isTimeout {
+				m.handleTimeout()
+			}
+			errorResult <- errors.Wrapf(err, "got error processing request")
+			return nil
+		},
+		m.defaultTtl)
+
+	if err != nil {
+		return nil, errors.Wrap(err, "got error sending property description read request")
+	}
+
+	select {
+	case response := <-result:
+		return response, nil
+	case errorResponse := <-errorResult:
+		return nil, errorResponse
+	}
+}
+
+func (m *Connection) sendDeviceMemoryReadRequest(targetAddress driverModel.KnxAddress, address uint16, numBytes uint8) (*driverModel.ApduDataMemoryResponse, error) {
+	// Next, read the device descriptor so we know how we have to communicate with the device.
+	counter := m.getNextCounter(targetAddress)
+
+	// Send the property read request and wait for a confirmation that this property is readable.
+	propertyReadRequest := driverModel.NewTunnelingRequest(
+		driverModel.NewTunnelingRequestDataBlock(m.CommunicationChannelId, m.getNewSequenceCounter()),
+		driverModel.NewLDataReq(
+			0,
+			nil,
+			driverModel.NewLDataExtended(
+				false,
+				6,
+				0,
+				driverModel.NewKnxAddress(0, 0, 0),
+				KnxAddressToByteArray(targetAddress),
+				driverModel.NewApduDataContainer(
+					driverModel.NewApduDataMemoryRead(numBytes, address, 0).GetParent(),
+					true,
+					counter,
+					0,
+				).GetParent(),
+				true,
+				true,
+				driverModel.CEMIPriority_LOW,
+				false,
+				false,
+			).GetParent(),
+			0,
+		).GetParent(),
+		0,
+	)
+
+	result := make(chan *driverModel.ApduDataMemoryResponse)
+	errorResult := make(chan error)
+	err := m.messageCodec.SendRequest(
+		propertyReadRequest,
+		func(message interface{}) bool {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			if tunnelingRequest == nil ||
+				tunnelingRequest.TunnelingRequestDataBlock.CommunicationChannelId != m.CommunicationChannelId {
+				return false
+			}
+			lDataInd := driverModel.CastLDataInd(tunnelingRequest.Cemi)
+			if lDataInd == nil {
+				return false
+			}
+			dataFrameExt := driverModel.CastLDataExtended(lDataInd.DataFrame)
+			if dataFrameExt == nil {
+				return false
+			}
+			dataContainer := driverModel.CastApduDataContainer(dataFrameExt.Apdu)
+			if dataContainer == nil {
+				return false
+			}
+			dataApduMemoryResponse := driverModel.CastApduDataMemoryResponse(dataContainer.DataApdu)
+			if dataApduMemoryResponse == nil {
+				return false
+			}
+
+			// Check if the address matches
+			if *dataFrameExt.SourceAddress != targetAddress {
+				return false
+			}
+			// Check if the counter matches
+			if dataFrameExt.Apdu.Counter != counter {
+				return false
+			}
+			return dataApduMemoryResponse.Address == address
+		},
+		func(message interface{}) error {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			lDataInd := driverModel.CastLDataInd(tunnelingRequest.Cemi)
+			dataFrameExt := driverModel.CastLDataExtended(lDataInd.DataFrame)
+			dataContainer := driverModel.CastApduDataContainer(dataFrameExt.Apdu)
+			dataApduMemoryResponse := driverModel.CastApduDataMemoryResponse(dataContainer.DataApdu)
+
+			// Acknowledge the receipt
+			_ = m.sendDeviceAck(targetAddress, dataFrameExt.Apdu.Counter, func(err error) {
+				// If the error flag is set, there was an error authenticating
+				if lDataInd.DataFrame.ErrorFlag {
+					errorResult <- errors.Errorf("error reading memory from device: %s", KnxAddressToString(&targetAddress))
+				} else if err != nil {
+					errorResult <- errors.Errorf("error sending ack to device: %s", KnxAddressToString(&targetAddress))
+				} else {
+					result <- dataApduMemoryResponse
+				}
+			})
+
+			return nil
+		},
+		func(err error) error {
+			// If this is a timeout, do a check if the connection requires a reconnection
+			if _, isTimeout := err.(plcerrors.TimeoutError); isTimeout {
+				m.handleTimeout()
+			}
+			errorResult <- errors.Wrap(err, "got error processing request")
+			return nil
+		},
+		m.defaultTtl)
+
+	if err != nil {
+		return nil, errors.Wrap(err, "got error sending memory read request")
+	}
+
+	select {
+	case response := <-result:
+		return response, nil
+	case errorResponse := <-errorResult:
+		return nil, errorResponse
+	}
+}
+
+func (m *Connection) sendDeviceAck(targetAddress driverModel.KnxAddress, counter uint8, callback func(err error)) error {
+	ack := driverModel.NewTunnelingRequest(
+		driverModel.NewTunnelingRequestDataBlock(m.CommunicationChannelId, m.getNewSequenceCounter()),
+		driverModel.NewLDataReq(
+			0,
+			nil,
+			driverModel.NewLDataExtended(
+				false,
+				6,
+				uint8(0),
+				driverModel.NewKnxAddress(0, 0, 0), KnxAddressToByteArray(targetAddress),
+				driverModel.NewApduControlContainer(driverModel.NewApduControlAck().GetParent(), true, counter, 0).GetParent(),
+				true,
+				true,
+				driverModel.CEMIPriority_SYSTEM,
+				false,
+				false,
+			).GetParent(),
+			0,
+		).GetParent(),
+		0,
+	)
+
+	err := m.messageCodec.SendRequest(
+		ack,
+		func(message interface{}) bool {
+			tunnelingRequest := driverModel.CastTunnelingRequest(message)
+			if tunnelingRequest == nil ||
+				tunnelingRequest.TunnelingRequestDataBlock.CommunicationChannelId != m.CommunicationChannelId {
+				return false
+			}
+			lDataCon := driverModel.CastLDataCon(tunnelingRequest.Cemi)
+			if lDataCon == nil {
+				return false
+			}
+			dataFrameExt := driverModel.CastLDataExtended(lDataCon.DataFrame)
+			if dataFrameExt == nil {
+				return false
+			}
+			// Check if the addresses match
+			if *dataFrameExt.SourceAddress != *m.ClientKnxAddress {
+				return false
+			}
+			curTargetAddress := ByteArrayToKnxAddress(dataFrameExt.DestinationAddress)
+			if *curTargetAddress != targetAddress {
+				return false
+			}
+			// Check if the counter matches
+			if dataFrameExt.Apdu.Counter != counter {
+				return false
+			}
+			controlContainer := driverModel.CastApduControlContainer(dataFrameExt.Apdu)
+			if controlContainer == nil {
+				return false
+			}
+			dataApduAck := driverModel.CastApduControlAck(controlContainer.ControlApdu)
+			if dataApduAck == nil {
+				return false
+			}
+			return true
+		},
+		func(message interface{}) error {
+			callback(nil)
+			return nil
+		},
+		func(err error) error {
+			// If this is a timeout, do a check if the connection requires a reconnection
+			if _, isTimeout := err.(plcerrors.TimeoutError); isTimeout {
+				m.handleTimeout()
+			}
+			callback(errors.Wrap(err, "got error processing request"))
+			return nil
+		},
+		m.defaultTtl)
+
+	if err != nil {
+		return errors.Wrap(err, "got error sending ack request")
+	}
+
+	return nil
+}
diff --git a/plc4go/internal/knxnetip/Discoverer.go b/plc4go/internal/knxnetip/Discoverer.go
new file mode 100644
index 0000000000..c1b40ab6de
--- /dev/null
+++ b/plc4go/internal/knxnetip/Discoverer.go
@@ -0,0 +1,190 @@
+/*
+ * 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 knxnetip
+
+import (
+	"bytes"
+	"fmt"
+	"github.com/apache/plc4x/plc4go/internal/spi/options"
+	"github.com/pkg/errors"
+	"net"
+	"net/url"
+	"time"
+
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	internalModel "github.com/apache/plc4x/plc4go/internal/spi/model"
+	"github.com/apache/plc4x/plc4go/internal/spi/transports"
+	"github.com/apache/plc4x/plc4go/internal/spi/transports/udp"
+	apiModel "github.com/apache/plc4x/plc4go/pkg/plc4go/model"
+	driverModel "github.com/apache/plc4x/plc4go/protocols/knxnetip/readwrite/model"
+)
+
+type Discoverer struct {
+	messageCodec spi.MessageCodec
+}
+
+func NewDiscoverer() *Discoverer {
+	return &Discoverer{}
+}
+
+func (d *Discoverer) Discover(callback func(event apiModel.PlcDiscoveryEvent), discoveryOptions ...options.WithDiscoveryOption) error {
+	udpTransport := udp.NewTransport()
+
+	// Create a connection string for the KNX broadcast discovery address.
+	connectionUrl, err := url.Parse("udp://224.0.23.12:3671")
+	if err != nil {
+		return err
+	}
+
+	allInterfaces, err := net.Interfaces()
+	if err != nil {
+		return err
+	}
+
+	// If no device is explicitly selected via option, simply use all of them
+	// However if a discovery option is present to select a device by name, only
+	// add those devices matching any of the given names.
+	var interfaces []net.Interface
+	deviceNames := options.FilterDiscoveryOptionsDeviceName(discoveryOptions)
+	if len(deviceNames) > 0 {
+		for _, curInterface := range allInterfaces {
+			for _, deviceNameOption := range deviceNames {
+				if curInterface.Name == deviceNameOption.GetDeviceName() {
+					interfaces = append(interfaces, curInterface)
+					break
+				}
+			}
+		}
+	} else {
+		interfaces = allInterfaces
+	}
+
+	var tranportInstances []transports.TransportInstance
+	// Iterate over all network devices of this system.
+	for _, interf := range interfaces {
+		addrs, err := interf.Addrs()
+		if err != nil {
+			return err
+		}
+		// Iterate over all addresses the current interface has configured
+		// For KNX we're only interested in IPv4 addresses, as it doesn't
+		// seem to work with IPv6.
+		for _, addr := range addrs {
+			var ipv4Addr net.IP
+			switch addr.(type) {
+			// If the device is configured to communicate with a subnet
+			case *net.IPNet:
+				ipv4Addr = addr.(*net.IPNet).IP.To4()
+
+			// If the device is configured for a point-to-point connection
+			case *net.IPAddr:
+				ipv4Addr = addr.(*net.IPAddr).IP.To4()
+			}
+
+			// If we found an IPv4 address and this is not a loopback address,
+			// add it to the list of devices we will open ports and send discovery
+			// messages from.
+			if ipv4Addr != nil && !ipv4Addr.IsLoopback() {
+				// Create a new "connection" (Actually open a local udp socket and target outgoing packets to that address)
+				transportInstance, err :=
... 703317 lines suppressed ...