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 ...