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

cdutz pushed a commit to branch chore/profinet-phase-3
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 95a8648d03ab1bd0ec041f63ff424cbd42c7c1ff
Author: Christofer Dutz <[email protected]>
AuthorDate: Wed May 31 15:02:37 2023 +0200

    chore(plc4j/profinet): Tried adjusting the code to provide more help in 
error messages and started working on handling the "ping" messages.
---
 .../protocols/eip/readwrite/model/CipIdentity.go   | 636 +++++++++++++++++++++
 .../eip/readwrite/model/CipSecurityInformation.go  | 250 ++++++++
 .../eip/readwrite/model/CommandSpecificDataItem.go | 196 +++++++
 .../eip/readwrite/model/EipListIdentityRequest.go  | 180 ++++++
 .../eip/readwrite/model/EipListIdentityResponse.go | 270 +++++++++
 .../java/profinet/readwrite/DceRpc_Packet.java     |  26 +-
 .../java/profinet/readwrite/PnIoCm_Packet.java     |   2 +
 .../profinet/readwrite/PnIoCm_Packet_Working.java  | 122 ++++
 .../java/profinet/device/ProfinetChannel.java      |  31 +-
 .../plc4x/java/profinet/device/ProfinetDevice.java |   5 +
 .../profinet/discovery/ProfinetPlcDiscoverer.java  |   1 +
 .../profinet/protocol/ProfinetProtocolLogic.java   |  11 +-
 .../plc4x/java/profinet/ManualProfinetIoTest.java  |   8 +-
 .../plc4x/java/profinet/ProfinetCheckSumTests.java |   1 +
 .../main/resources/protocols/profinet/dcerpc.mspec |   3 +-
 .../main/resources/protocols/profinet/pnio.mspec   |   2 +
 16 files changed, 1723 insertions(+), 21 deletions(-)

diff --git a/plc4go/protocols/eip/readwrite/model/CipIdentity.go 
b/plc4go/protocols/eip/readwrite/model/CipIdentity.go
new file mode 100644
index 0000000000..29a2bc90ce
--- /dev/null
+++ b/plc4go/protocols/eip/readwrite/model/CipIdentity.go
@@ -0,0 +1,636 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package model
+
+import (
+       "context"
+       "fmt"
+       "github.com/apache/plc4x/plc4go/spi/utils"
+       "github.com/pkg/errors"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// Constant values.
+const CipIdentity_ZEROES1 uint32 = 0x00000000
+const CipIdentity_ZEROES2 uint32 = 0x00000000
+
+// CipIdentity is the corresponding interface of CipIdentity
+type CipIdentity interface {
+       fmt.Stringer
+       utils.LengthAware
+       utils.Serializable
+       CommandSpecificDataItem
+       // GetEncapsulationProtocolVersion returns EncapsulationProtocolVersion 
(property field)
+       GetEncapsulationProtocolVersion() uint16
+       // GetSocketAddressFamily returns SocketAddressFamily (property field)
+       GetSocketAddressFamily() uint16
+       // GetSocketAddressPort returns SocketAddressPort (property field)
+       GetSocketAddressPort() uint16
+       // GetSocketAddressAddress returns SocketAddressAddress (property field)
+       GetSocketAddressAddress() []uint8
+       // GetVendorId returns VendorId (property field)
+       GetVendorId() uint16
+       // GetDeviceType returns DeviceType (property field)
+       GetDeviceType() uint16
+       // GetProductCode returns ProductCode (property field)
+       GetProductCode() uint16
+       // GetRevisionMajor returns RevisionMajor (property field)
+       GetRevisionMajor() uint8
+       // GetRevisionMinor returns RevisionMinor (property field)
+       GetRevisionMinor() uint8
+       // GetStatus returns Status (property field)
+       GetStatus() uint16
+       // GetSerialNumber returns SerialNumber (property field)
+       GetSerialNumber() uint32
+       // GetProductName returns ProductName (property field)
+       GetProductName() string
+       // GetState returns State (property field)
+       GetState() uint8
+}
+
+// CipIdentityExactly can be used when we want exactly this type and not a 
type which fulfills CipIdentity.
+// This is useful for switch cases.
+type CipIdentityExactly interface {
+       CipIdentity
+       isCipIdentity() bool
+}
+
+// _CipIdentity is the data-structure of this message
+type _CipIdentity struct {
+       *_CommandSpecificDataItem
+       EncapsulationProtocolVersion uint16
+       SocketAddressFamily          uint16
+       SocketAddressPort            uint16
+       SocketAddressAddress         []uint8
+       VendorId                     uint16
+       DeviceType                   uint16
+       ProductCode                  uint16
+       RevisionMajor                uint8
+       RevisionMinor                uint8
+       Status                       uint16
+       SerialNumber                 uint32
+       ProductName                  string
+       State                        uint8
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for discriminator values.
+///////////////////////
+
+func (m *_CipIdentity) GetItemType() uint16 {
+       return 0x000C
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+func (m *_CipIdentity) InitializeParent(parent CommandSpecificDataItem) {}
+
+func (m *_CipIdentity) GetParent() CommandSpecificDataItem {
+       return m._CommandSpecificDataItem
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for property fields.
+///////////////////////
+
+func (m *_CipIdentity) GetEncapsulationProtocolVersion() uint16 {
+       return m.EncapsulationProtocolVersion
+}
+
+func (m *_CipIdentity) GetSocketAddressFamily() uint16 {
+       return m.SocketAddressFamily
+}
+
+func (m *_CipIdentity) GetSocketAddressPort() uint16 {
+       return m.SocketAddressPort
+}
+
+func (m *_CipIdentity) GetSocketAddressAddress() []uint8 {
+       return m.SocketAddressAddress
+}
+
+func (m *_CipIdentity) GetVendorId() uint16 {
+       return m.VendorId
+}
+
+func (m *_CipIdentity) GetDeviceType() uint16 {
+       return m.DeviceType
+}
+
+func (m *_CipIdentity) GetProductCode() uint16 {
+       return m.ProductCode
+}
+
+func (m *_CipIdentity) GetRevisionMajor() uint8 {
+       return m.RevisionMajor
+}
+
+func (m *_CipIdentity) GetRevisionMinor() uint8 {
+       return m.RevisionMinor
+}
+
+func (m *_CipIdentity) GetStatus() uint16 {
+       return m.Status
+}
+
+func (m *_CipIdentity) GetSerialNumber() uint32 {
+       return m.SerialNumber
+}
+
+func (m *_CipIdentity) GetProductName() string {
+       return m.ProductName
+}
+
+func (m *_CipIdentity) GetState() uint8 {
+       return m.State
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for const fields.
+///////////////////////
+
+func (m *_CipIdentity) GetZeroes1() uint32 {
+       return CipIdentity_ZEROES1
+}
+
+func (m *_CipIdentity) GetZeroes2() uint32 {
+       return CipIdentity_ZEROES2
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+// NewCipIdentity factory function for _CipIdentity
+func NewCipIdentity(encapsulationProtocolVersion uint16, socketAddressFamily 
uint16, socketAddressPort uint16, socketAddressAddress []uint8, vendorId 
uint16, deviceType uint16, productCode uint16, revisionMajor uint8, 
revisionMinor uint8, status uint16, serialNumber uint32, productName string, 
state uint8) *_CipIdentity {
+       _result := &_CipIdentity{
+               EncapsulationProtocolVersion: encapsulationProtocolVersion,
+               SocketAddressFamily:          socketAddressFamily,
+               SocketAddressPort:            socketAddressPort,
+               SocketAddressAddress:         socketAddressAddress,
+               VendorId:                     vendorId,
+               DeviceType:                   deviceType,
+               ProductCode:                  productCode,
+               RevisionMajor:                revisionMajor,
+               RevisionMinor:                revisionMinor,
+               Status:                       status,
+               SerialNumber:                 serialNumber,
+               ProductName:                  productName,
+               State:                        state,
+               _CommandSpecificDataItem:     NewCommandSpecificDataItem(),
+       }
+       
_result._CommandSpecificDataItem._CommandSpecificDataItemChildRequirements = 
_result
+       return _result
+}
+
+// Deprecated: use the interface for direct cast
+func CastCipIdentity(structType any) CipIdentity {
+       if casted, ok := structType.(CipIdentity); ok {
+               return casted
+       }
+       if casted, ok := structType.(*CipIdentity); ok {
+               return *casted
+       }
+       return nil
+}
+
+func (m *_CipIdentity) GetTypeName() string {
+       return "CipIdentity"
+}
+
+func (m *_CipIdentity) GetLengthInBits(ctx context.Context) uint16 {
+       lengthInBits := uint16(m.GetParentLengthInBits(ctx))
+
+       // Implicit Field (itemLength)
+       lengthInBits += 16
+
+       // Simple field (encapsulationProtocolVersion)
+       lengthInBits += 16
+
+       // Simple field (socketAddressFamily)
+       lengthInBits += 16
+
+       // Simple field (socketAddressPort)
+       lengthInBits += 16
+
+       // Array field
+       if len(m.SocketAddressAddress) > 0 {
+               lengthInBits += 8 * uint16(len(m.SocketAddressAddress))
+       }
+
+       // Const Field (zeroes1)
+       lengthInBits += 32
+
+       // Const Field (zeroes2)
+       lengthInBits += 32
+
+       // Simple field (vendorId)
+       lengthInBits += 16
+
+       // Simple field (deviceType)
+       lengthInBits += 16
+
+       // Simple field (productCode)
+       lengthInBits += 16
+
+       // Simple field (revisionMajor)
+       lengthInBits += 8
+
+       // Simple field (revisionMinor)
+       lengthInBits += 8
+
+       // Simple field (status)
+       lengthInBits += 16
+
+       // Simple field (serialNumber)
+       lengthInBits += 32
+
+       // Implicit Field (productNameLength)
+       lengthInBits += 8
+
+       // Simple field (productName)
+       lengthInBits += uint16(int32(uint8(len(m.GetProductName()))) * 
int32(int32(8)))
+
+       // Simple field (state)
+       lengthInBits += 8
+
+       return lengthInBits
+}
+
+func (m *_CipIdentity) GetLengthInBytes(ctx context.Context) uint16 {
+       return m.GetLengthInBits(ctx) / 8
+}
+
+func CipIdentityParse(theBytes []byte) (CipIdentity, error) {
+       return CipIdentityParseWithBuffer(context.Background(), 
utils.NewReadBufferByteBased(theBytes))
+}
+
+func CipIdentityParseWithBuffer(ctx context.Context, readBuffer 
utils.ReadBuffer) (CipIdentity, error) {
+       positionAware := readBuffer
+       _ = positionAware
+       if pullErr := readBuffer.PullContext("CipIdentity"); pullErr != nil {
+               return nil, errors.Wrap(pullErr, "Error pulling for 
CipIdentity")
+       }
+       currentPos := positionAware.GetPos()
+       _ = currentPos
+
+       // Implicit Field (itemLength) (Used for parsing, but its value is not 
stored as it's implicitly given by the objects content)
+       itemLength, _itemLengthErr := readBuffer.ReadUint16("itemLength", 16)
+       _ = itemLength
+       if _itemLengthErr != nil {
+               return nil, errors.Wrap(_itemLengthErr, "Error parsing 
'itemLength' field of CipIdentity")
+       }
+
+       // Simple Field (encapsulationProtocolVersion)
+       _encapsulationProtocolVersion, _encapsulationProtocolVersionErr := 
readBuffer.ReadUint16("encapsulationProtocolVersion", 16)
+       if _encapsulationProtocolVersionErr != nil {
+               return nil, errors.Wrap(_encapsulationProtocolVersionErr, 
"Error parsing 'encapsulationProtocolVersion' field of CipIdentity")
+       }
+       encapsulationProtocolVersion := _encapsulationProtocolVersion
+
+       // Simple Field (socketAddressFamily)
+       _socketAddressFamily, _socketAddressFamilyErr := 
readBuffer.ReadUint16("socketAddressFamily", 16)
+       if _socketAddressFamilyErr != nil {
+               return nil, errors.Wrap(_socketAddressFamilyErr, "Error parsing 
'socketAddressFamily' field of CipIdentity")
+       }
+       socketAddressFamily := _socketAddressFamily
+
+       // Simple Field (socketAddressPort)
+       _socketAddressPort, _socketAddressPortErr := 
readBuffer.ReadUint16("socketAddressPort", 16)
+       if _socketAddressPortErr != nil {
+               return nil, errors.Wrap(_socketAddressPortErr, "Error parsing 
'socketAddressPort' field of CipIdentity")
+       }
+       socketAddressPort := _socketAddressPort
+
+       // Array field (socketAddressAddress)
+       if pullErr := readBuffer.PullContext("socketAddressAddress", 
utils.WithRenderAsList(true)); pullErr != nil {
+               return nil, errors.Wrap(pullErr, "Error pulling for 
socketAddressAddress")
+       }
+       // Count array
+       socketAddressAddress := make([]uint8, uint16(4))
+       // This happens when the size is set conditional to 0
+       if len(socketAddressAddress) == 0 {
+               socketAddressAddress = nil
+       }
+       {
+               _numItems := uint16(uint16(4))
+               for _curItem := uint16(0); _curItem < _numItems; _curItem++ {
+                       arrayCtx := utils.CreateArrayContext(ctx, 
int(_numItems), int(_curItem))
+                       _ = arrayCtx
+                       _ = _curItem
+                       _item, _err := readBuffer.ReadUint8("", 8)
+                       if _err != nil {
+                               return nil, errors.Wrap(_err, "Error parsing 
'socketAddressAddress' field of CipIdentity")
+                       }
+                       socketAddressAddress[_curItem] = _item
+               }
+       }
+       if closeErr := readBuffer.CloseContext("socketAddressAddress", 
utils.WithRenderAsList(true)); closeErr != nil {
+               return nil, errors.Wrap(closeErr, "Error closing for 
socketAddressAddress")
+       }
+
+       // Const Field (zeroes1)
+       zeroes1, _zeroes1Err := readBuffer.ReadUint32("zeroes1", 32)
+       if _zeroes1Err != nil {
+               return nil, errors.Wrap(_zeroes1Err, "Error parsing 'zeroes1' 
field of CipIdentity")
+       }
+       if zeroes1 != CipIdentity_ZEROES1 {
+               return nil, errors.New("Expected constant value " + 
fmt.Sprintf("%d", CipIdentity_ZEROES1) + " but got " + fmt.Sprintf("%d", 
zeroes1))
+       }
+
+       // Const Field (zeroes2)
+       zeroes2, _zeroes2Err := readBuffer.ReadUint32("zeroes2", 32)
+       if _zeroes2Err != nil {
+               return nil, errors.Wrap(_zeroes2Err, "Error parsing 'zeroes2' 
field of CipIdentity")
+       }
+       if zeroes2 != CipIdentity_ZEROES2 {
+               return nil, errors.New("Expected constant value " + 
fmt.Sprintf("%d", CipIdentity_ZEROES2) + " but got " + fmt.Sprintf("%d", 
zeroes2))
+       }
+
+       // Simple Field (vendorId)
+       _vendorId, _vendorIdErr := readBuffer.ReadUint16("vendorId", 16)
+       if _vendorIdErr != nil {
+               return nil, errors.Wrap(_vendorIdErr, "Error parsing 'vendorId' 
field of CipIdentity")
+       }
+       vendorId := _vendorId
+
+       // Simple Field (deviceType)
+       _deviceType, _deviceTypeErr := readBuffer.ReadUint16("deviceType", 16)
+       if _deviceTypeErr != nil {
+               return nil, errors.Wrap(_deviceTypeErr, "Error parsing 
'deviceType' field of CipIdentity")
+       }
+       deviceType := _deviceType
+
+       // Simple Field (productCode)
+       _productCode, _productCodeErr := readBuffer.ReadUint16("productCode", 
16)
+       if _productCodeErr != nil {
+               return nil, errors.Wrap(_productCodeErr, "Error parsing 
'productCode' field of CipIdentity")
+       }
+       productCode := _productCode
+
+       // Simple Field (revisionMajor)
+       _revisionMajor, _revisionMajorErr := 
readBuffer.ReadUint8("revisionMajor", 8)
+       if _revisionMajorErr != nil {
+               return nil, errors.Wrap(_revisionMajorErr, "Error parsing 
'revisionMajor' field of CipIdentity")
+       }
+       revisionMajor := _revisionMajor
+
+       // Simple Field (revisionMinor)
+       _revisionMinor, _revisionMinorErr := 
readBuffer.ReadUint8("revisionMinor", 8)
+       if _revisionMinorErr != nil {
+               return nil, errors.Wrap(_revisionMinorErr, "Error parsing 
'revisionMinor' field of CipIdentity")
+       }
+       revisionMinor := _revisionMinor
+
+       // Simple Field (status)
+       _status, _statusErr := readBuffer.ReadUint16("status", 16)
+       if _statusErr != nil {
+               return nil, errors.Wrap(_statusErr, "Error parsing 'status' 
field of CipIdentity")
+       }
+       status := _status
+
+       // Simple Field (serialNumber)
+       _serialNumber, _serialNumberErr := 
readBuffer.ReadUint32("serialNumber", 32)
+       if _serialNumberErr != nil {
+               return nil, errors.Wrap(_serialNumberErr, "Error parsing 
'serialNumber' field of CipIdentity")
+       }
+       serialNumber := _serialNumber
+
+       // Implicit Field (productNameLength) (Used for parsing, but its value 
is not stored as it's implicitly given by the objects content)
+       productNameLength, _productNameLengthErr := 
readBuffer.ReadUint8("productNameLength", 8)
+       _ = productNameLength
+       if _productNameLengthErr != nil {
+               return nil, errors.Wrap(_productNameLengthErr, "Error parsing 
'productNameLength' field of CipIdentity")
+       }
+
+       // Simple Field (productName)
+       _productName, _productNameErr := readBuffer.ReadString("productName", 
uint32((productNameLength)*(8)), "UTF-8")
+       if _productNameErr != nil {
+               return nil, errors.Wrap(_productNameErr, "Error parsing 
'productName' field of CipIdentity")
+       }
+       productName := _productName
+
+       // Simple Field (state)
+       _state, _stateErr := readBuffer.ReadUint8("state", 8)
+       if _stateErr != nil {
+               return nil, errors.Wrap(_stateErr, "Error parsing 'state' field 
of CipIdentity")
+       }
+       state := _state
+
+       if closeErr := readBuffer.CloseContext("CipIdentity"); closeErr != nil {
+               return nil, errors.Wrap(closeErr, "Error closing for 
CipIdentity")
+       }
+
+       // Create a partially initialized instance
+       _child := &_CipIdentity{
+               _CommandSpecificDataItem:     &_CommandSpecificDataItem{},
+               EncapsulationProtocolVersion: encapsulationProtocolVersion,
+               SocketAddressFamily:          socketAddressFamily,
+               SocketAddressPort:            socketAddressPort,
+               SocketAddressAddress:         socketAddressAddress,
+               VendorId:                     vendorId,
+               DeviceType:                   deviceType,
+               ProductCode:                  productCode,
+               RevisionMajor:                revisionMajor,
+               RevisionMinor:                revisionMinor,
+               Status:                       status,
+               SerialNumber:                 serialNumber,
+               ProductName:                  productName,
+               State:                        state,
+       }
+       
_child._CommandSpecificDataItem._CommandSpecificDataItemChildRequirements = 
_child
+       return _child, nil
+}
+
+func (m *_CipIdentity) Serialize() ([]byte, error) {
+       wb := 
utils.NewWriteBufferByteBased(utils.WithInitialSizeForByteBasedBuffer(int(m.GetLengthInBytes(context.Background()))))
+       if err := m.SerializeWithWriteBuffer(context.Background(), wb); err != 
nil {
+               return nil, err
+       }
+       return wb.GetBytes(), nil
+}
+
+func (m *_CipIdentity) SerializeWithWriteBuffer(ctx context.Context, 
writeBuffer utils.WriteBuffer) error {
+       positionAware := writeBuffer
+       _ = positionAware
+       ser := func() error {
+               if pushErr := writeBuffer.PushContext("CipIdentity"); pushErr 
!= nil {
+                       return errors.Wrap(pushErr, "Error pushing for 
CipIdentity")
+               }
+
+               // Implicit Field (itemLength) (Used for parsing, but it's 
value is not stored as it's implicitly given by the objects content)
+               itemLength := uint16(uint16(uint16(34)) + 
uint16(uint8(len(m.GetProductName()))))
+               _itemLengthErr := writeBuffer.WriteUint16("itemLength", 16, 
(itemLength))
+               if _itemLengthErr != nil {
+                       return errors.Wrap(_itemLengthErr, "Error serializing 
'itemLength' field")
+               }
+
+               // Simple Field (encapsulationProtocolVersion)
+               encapsulationProtocolVersion := 
uint16(m.GetEncapsulationProtocolVersion())
+               _encapsulationProtocolVersionErr := 
writeBuffer.WriteUint16("encapsulationProtocolVersion", 16, 
(encapsulationProtocolVersion))
+               if _encapsulationProtocolVersionErr != nil {
+                       return errors.Wrap(_encapsulationProtocolVersionErr, 
"Error serializing 'encapsulationProtocolVersion' field")
+               }
+
+               // Simple Field (socketAddressFamily)
+               socketAddressFamily := uint16(m.GetSocketAddressFamily())
+               _socketAddressFamilyErr := 
writeBuffer.WriteUint16("socketAddressFamily", 16, (socketAddressFamily))
+               if _socketAddressFamilyErr != nil {
+                       return errors.Wrap(_socketAddressFamilyErr, "Error 
serializing 'socketAddressFamily' field")
+               }
+
+               // Simple Field (socketAddressPort)
+               socketAddressPort := uint16(m.GetSocketAddressPort())
+               _socketAddressPortErr := 
writeBuffer.WriteUint16("socketAddressPort", 16, (socketAddressPort))
+               if _socketAddressPortErr != nil {
+                       return errors.Wrap(_socketAddressPortErr, "Error 
serializing 'socketAddressPort' field")
+               }
+
+               // Array Field (socketAddressAddress)
+               if pushErr := writeBuffer.PushContext("socketAddressAddress", 
utils.WithRenderAsList(true)); pushErr != nil {
+                       return errors.Wrap(pushErr, "Error pushing for 
socketAddressAddress")
+               }
+               for _curItem, _element := range m.GetSocketAddressAddress() {
+                       _ = _curItem
+                       _elementErr := writeBuffer.WriteUint8("", 8, _element)
+                       if _elementErr != nil {
+                               return errors.Wrap(_elementErr, "Error 
serializing 'socketAddressAddress' field")
+                       }
+               }
+               if popErr := writeBuffer.PopContext("socketAddressAddress", 
utils.WithRenderAsList(true)); popErr != nil {
+                       return errors.Wrap(popErr, "Error popping for 
socketAddressAddress")
+               }
+
+               // Const Field (zeroes1)
+               _zeroes1Err := writeBuffer.WriteUint32("zeroes1", 32, 
0x00000000)
+               if _zeroes1Err != nil {
+                       return errors.Wrap(_zeroes1Err, "Error serializing 
'zeroes1' field")
+               }
+
+               // Const Field (zeroes2)
+               _zeroes2Err := writeBuffer.WriteUint32("zeroes2", 32, 
0x00000000)
+               if _zeroes2Err != nil {
+                       return errors.Wrap(_zeroes2Err, "Error serializing 
'zeroes2' field")
+               }
+
+               // Simple Field (vendorId)
+               vendorId := uint16(m.GetVendorId())
+               _vendorIdErr := writeBuffer.WriteUint16("vendorId", 16, 
(vendorId))
+               if _vendorIdErr != nil {
+                       return errors.Wrap(_vendorIdErr, "Error serializing 
'vendorId' field")
+               }
+
+               // Simple Field (deviceType)
+               deviceType := uint16(m.GetDeviceType())
+               _deviceTypeErr := writeBuffer.WriteUint16("deviceType", 16, 
(deviceType))
+               if _deviceTypeErr != nil {
+                       return errors.Wrap(_deviceTypeErr, "Error serializing 
'deviceType' field")
+               }
+
+               // Simple Field (productCode)
+               productCode := uint16(m.GetProductCode())
+               _productCodeErr := writeBuffer.WriteUint16("productCode", 16, 
(productCode))
+               if _productCodeErr != nil {
+                       return errors.Wrap(_productCodeErr, "Error serializing 
'productCode' field")
+               }
+
+               // Simple Field (revisionMajor)
+               revisionMajor := uint8(m.GetRevisionMajor())
+               _revisionMajorErr := writeBuffer.WriteUint8("revisionMajor", 8, 
(revisionMajor))
+               if _revisionMajorErr != nil {
+                       return errors.Wrap(_revisionMajorErr, "Error 
serializing 'revisionMajor' field")
+               }
+
+               // Simple Field (revisionMinor)
+               revisionMinor := uint8(m.GetRevisionMinor())
+               _revisionMinorErr := writeBuffer.WriteUint8("revisionMinor", 8, 
(revisionMinor))
+               if _revisionMinorErr != nil {
+                       return errors.Wrap(_revisionMinorErr, "Error 
serializing 'revisionMinor' field")
+               }
+
+               // Simple Field (status)
+               status := uint16(m.GetStatus())
+               _statusErr := writeBuffer.WriteUint16("status", 16, (status))
+               if _statusErr != nil {
+                       return errors.Wrap(_statusErr, "Error serializing 
'status' field")
+               }
+
+               // Simple Field (serialNumber)
+               serialNumber := uint32(m.GetSerialNumber())
+               _serialNumberErr := writeBuffer.WriteUint32("serialNumber", 32, 
(serialNumber))
+               if _serialNumberErr != nil {
+                       return errors.Wrap(_serialNumberErr, "Error serializing 
'serialNumber' field")
+               }
+
+               // Implicit Field (productNameLength) (Used for parsing, but 
it's value is not stored as it's implicitly given by the objects content)
+               productNameLength := uint8(uint8(len(m.GetProductName())))
+               _productNameLengthErr := 
writeBuffer.WriteUint8("productNameLength", 8, (productNameLength))
+               if _productNameLengthErr != nil {
+                       return errors.Wrap(_productNameLengthErr, "Error 
serializing 'productNameLength' field")
+               }
+
+               // Simple Field (productName)
+               productName := string(m.GetProductName())
+               _productNameErr := writeBuffer.WriteString("productName", 
uint32((uint8(len(m.GetProductName())))*(8)), "UTF-8", (productName))
+               if _productNameErr != nil {
+                       return errors.Wrap(_productNameErr, "Error serializing 
'productName' field")
+               }
+
+               // Simple Field (state)
+               state := uint8(m.GetState())
+               _stateErr := writeBuffer.WriteUint8("state", 8, (state))
+               if _stateErr != nil {
+                       return errors.Wrap(_stateErr, "Error serializing 
'state' field")
+               }
+
+               if popErr := writeBuffer.PopContext("CipIdentity"); popErr != 
nil {
+                       return errors.Wrap(popErr, "Error popping for 
CipIdentity")
+               }
+               return nil
+       }
+       return m.SerializeParent(ctx, writeBuffer, m, ser)
+}
+
+func (m *_CipIdentity) isCipIdentity() bool {
+       return true
+}
+
+func (m *_CipIdentity) String() string {
+       if m == nil {
+               return "<nil>"
+       }
+       writeBuffer := utils.NewWriteBufferBoxBasedWithOptions(true, true)
+       if err := writeBuffer.WriteSerializable(context.Background(), m); err 
!= nil {
+               return err.Error()
+       }
+       return writeBuffer.GetBox().String()
+}
diff --git a/plc4go/protocols/eip/readwrite/model/CipSecurityInformation.go 
b/plc4go/protocols/eip/readwrite/model/CipSecurityInformation.go
new file mode 100644
index 0000000000..739a638bf8
--- /dev/null
+++ b/plc4go/protocols/eip/readwrite/model/CipSecurityInformation.go
@@ -0,0 +1,250 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package model
+
+import (
+       "context"
+       "fmt"
+       "github.com/apache/plc4x/plc4go/spi/utils"
+       "github.com/pkg/errors"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// CipSecurityInformation is the corresponding interface of 
CipSecurityInformation
+type CipSecurityInformation interface {
+       fmt.Stringer
+       utils.LengthAware
+       utils.Serializable
+       CommandSpecificDataItem
+       // GetTodoImplement returns TodoImplement (property field)
+       GetTodoImplement() []uint8
+}
+
+// CipSecurityInformationExactly can be used when we want exactly this type 
and not a type which fulfills CipSecurityInformation.
+// This is useful for switch cases.
+type CipSecurityInformationExactly interface {
+       CipSecurityInformation
+       isCipSecurityInformation() bool
+}
+
+// _CipSecurityInformation is the data-structure of this message
+type _CipSecurityInformation struct {
+       *_CommandSpecificDataItem
+       TodoImplement []uint8
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for discriminator values.
+///////////////////////
+
+func (m *_CipSecurityInformation) GetItemType() uint16 {
+       return 0x0086
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+func (m *_CipSecurityInformation) InitializeParent(parent 
CommandSpecificDataItem) {}
+
+func (m *_CipSecurityInformation) GetParent() CommandSpecificDataItem {
+       return m._CommandSpecificDataItem
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for property fields.
+///////////////////////
+
+func (m *_CipSecurityInformation) GetTodoImplement() []uint8 {
+       return m.TodoImplement
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+// NewCipSecurityInformation factory function for _CipSecurityInformation
+func NewCipSecurityInformation(todoImplement []uint8) *_CipSecurityInformation 
{
+       _result := &_CipSecurityInformation{
+               TodoImplement:            todoImplement,
+               _CommandSpecificDataItem: NewCommandSpecificDataItem(),
+       }
+       
_result._CommandSpecificDataItem._CommandSpecificDataItemChildRequirements = 
_result
+       return _result
+}
+
+// Deprecated: use the interface for direct cast
+func CastCipSecurityInformation(structType any) CipSecurityInformation {
+       if casted, ok := structType.(CipSecurityInformation); ok {
+               return casted
+       }
+       if casted, ok := structType.(*CipSecurityInformation); ok {
+               return *casted
+       }
+       return nil
+}
+
+func (m *_CipSecurityInformation) GetTypeName() string {
+       return "CipSecurityInformation"
+}
+
+func (m *_CipSecurityInformation) GetLengthInBits(ctx context.Context) uint16 {
+       lengthInBits := uint16(m.GetParentLengthInBits(ctx))
+
+       // Implicit Field (itemLength)
+       lengthInBits += 16
+
+       // Array field
+       if len(m.TodoImplement) > 0 {
+               lengthInBits += 8 * uint16(len(m.TodoImplement))
+       }
+
+       return lengthInBits
+}
+
+func (m *_CipSecurityInformation) GetLengthInBytes(ctx context.Context) uint16 
{
+       return m.GetLengthInBits(ctx) / 8
+}
+
+func CipSecurityInformationParse(theBytes []byte) (CipSecurityInformation, 
error) {
+       return CipSecurityInformationParseWithBuffer(context.Background(), 
utils.NewReadBufferByteBased(theBytes))
+}
+
+func CipSecurityInformationParseWithBuffer(ctx context.Context, readBuffer 
utils.ReadBuffer) (CipSecurityInformation, error) {
+       positionAware := readBuffer
+       _ = positionAware
+       if pullErr := readBuffer.PullContext("CipSecurityInformation"); pullErr 
!= nil {
+               return nil, errors.Wrap(pullErr, "Error pulling for 
CipSecurityInformation")
+       }
+       currentPos := positionAware.GetPos()
+       _ = currentPos
+
+       // Implicit Field (itemLength) (Used for parsing, but its value is not 
stored as it's implicitly given by the objects content)
+       itemLength, _itemLengthErr := readBuffer.ReadUint16("itemLength", 16)
+       _ = itemLength
+       if _itemLengthErr != nil {
+               return nil, errors.Wrap(_itemLengthErr, "Error parsing 
'itemLength' field of CipSecurityInformation")
+       }
+
+       // Array field (todoImplement)
+       if pullErr := readBuffer.PullContext("todoImplement", 
utils.WithRenderAsList(true)); pullErr != nil {
+               return nil, errors.Wrap(pullErr, "Error pulling for 
todoImplement")
+       }
+       // Count array
+       todoImplement := make([]uint8, itemLength)
+       // This happens when the size is set conditional to 0
+       if len(todoImplement) == 0 {
+               todoImplement = nil
+       }
+       {
+               _numItems := uint16(itemLength)
+               for _curItem := uint16(0); _curItem < _numItems; _curItem++ {
+                       arrayCtx := utils.CreateArrayContext(ctx, 
int(_numItems), int(_curItem))
+                       _ = arrayCtx
+                       _ = _curItem
+                       _item, _err := readBuffer.ReadUint8("", 8)
+                       if _err != nil {
+                               return nil, errors.Wrap(_err, "Error parsing 
'todoImplement' field of CipSecurityInformation")
+                       }
+                       todoImplement[_curItem] = _item
+               }
+       }
+       if closeErr := readBuffer.CloseContext("todoImplement", 
utils.WithRenderAsList(true)); closeErr != nil {
+               return nil, errors.Wrap(closeErr, "Error closing for 
todoImplement")
+       }
+
+       if closeErr := readBuffer.CloseContext("CipSecurityInformation"); 
closeErr != nil {
+               return nil, errors.Wrap(closeErr, "Error closing for 
CipSecurityInformation")
+       }
+
+       // Create a partially initialized instance
+       _child := &_CipSecurityInformation{
+               _CommandSpecificDataItem: &_CommandSpecificDataItem{},
+               TodoImplement:            todoImplement,
+       }
+       
_child._CommandSpecificDataItem._CommandSpecificDataItemChildRequirements = 
_child
+       return _child, nil
+}
+
+func (m *_CipSecurityInformation) Serialize() ([]byte, error) {
+       wb := 
utils.NewWriteBufferByteBased(utils.WithInitialSizeForByteBasedBuffer(int(m.GetLengthInBytes(context.Background()))))
+       if err := m.SerializeWithWriteBuffer(context.Background(), wb); err != 
nil {
+               return nil, err
+       }
+       return wb.GetBytes(), nil
+}
+
+func (m *_CipSecurityInformation) SerializeWithWriteBuffer(ctx 
context.Context, writeBuffer utils.WriteBuffer) error {
+       positionAware := writeBuffer
+       _ = positionAware
+       ser := func() error {
+               if pushErr := 
writeBuffer.PushContext("CipSecurityInformation"); pushErr != nil {
+                       return errors.Wrap(pushErr, "Error pushing for 
CipSecurityInformation")
+               }
+
+               // Implicit Field (itemLength) (Used for parsing, but it's 
value is not stored as it's implicitly given by the objects content)
+               itemLength := uint16(uint16(len(m.GetTodoImplement())))
+               _itemLengthErr := writeBuffer.WriteUint16("itemLength", 16, 
(itemLength))
+               if _itemLengthErr != nil {
+                       return errors.Wrap(_itemLengthErr, "Error serializing 
'itemLength' field")
+               }
+
+               // Array Field (todoImplement)
+               if pushErr := writeBuffer.PushContext("todoImplement", 
utils.WithRenderAsList(true)); pushErr != nil {
+                       return errors.Wrap(pushErr, "Error pushing for 
todoImplement")
+               }
+               for _curItem, _element := range m.GetTodoImplement() {
+                       _ = _curItem
+                       _elementErr := writeBuffer.WriteUint8("", 8, _element)
+                       if _elementErr != nil {
+                               return errors.Wrap(_elementErr, "Error 
serializing 'todoImplement' field")
+                       }
+               }
+               if popErr := writeBuffer.PopContext("todoImplement", 
utils.WithRenderAsList(true)); popErr != nil {
+                       return errors.Wrap(popErr, "Error popping for 
todoImplement")
+               }
+
+               if popErr := writeBuffer.PopContext("CipSecurityInformation"); 
popErr != nil {
+                       return errors.Wrap(popErr, "Error popping for 
CipSecurityInformation")
+               }
+               return nil
+       }
+       return m.SerializeParent(ctx, writeBuffer, m, ser)
+}
+
+func (m *_CipSecurityInformation) isCipSecurityInformation() bool {
+       return true
+}
+
+func (m *_CipSecurityInformation) String() string {
+       if m == nil {
+               return "<nil>"
+       }
+       writeBuffer := utils.NewWriteBufferBoxBasedWithOptions(true, true)
+       if err := writeBuffer.WriteSerializable(context.Background(), m); err 
!= nil {
+               return err.Error()
+       }
+       return writeBuffer.GetBox().String()
+}
diff --git a/plc4go/protocols/eip/readwrite/model/CommandSpecificDataItem.go 
b/plc4go/protocols/eip/readwrite/model/CommandSpecificDataItem.go
new file mode 100644
index 0000000000..c2ad7b4761
--- /dev/null
+++ b/plc4go/protocols/eip/readwrite/model/CommandSpecificDataItem.go
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package model
+
+import (
+       "context"
+       "fmt"
+       "github.com/apache/plc4x/plc4go/spi/utils"
+       "github.com/pkg/errors"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// CommandSpecificDataItem is the corresponding interface of 
CommandSpecificDataItem
+type CommandSpecificDataItem interface {
+       fmt.Stringer
+       utils.LengthAware
+       utils.Serializable
+       // GetItemType returns ItemType (discriminator field)
+       GetItemType() uint16
+}
+
+// CommandSpecificDataItemExactly can be used when we want exactly this type 
and not a type which fulfills CommandSpecificDataItem.
+// This is useful for switch cases.
+type CommandSpecificDataItemExactly interface {
+       CommandSpecificDataItem
+       isCommandSpecificDataItem() bool
+}
+
+// _CommandSpecificDataItem is the data-structure of this message
+type _CommandSpecificDataItem struct {
+       _CommandSpecificDataItemChildRequirements
+}
+
+type _CommandSpecificDataItemChildRequirements interface {
+       utils.Serializable
+       GetLengthInBits(ctx context.Context) uint16
+       GetItemType() uint16
+}
+
+type CommandSpecificDataItemParent interface {
+       SerializeParent(ctx context.Context, writeBuffer utils.WriteBuffer, 
child CommandSpecificDataItem, serializeChildFunction func() error) error
+       GetTypeName() string
+}
+
+type CommandSpecificDataItemChild interface {
+       utils.Serializable
+       InitializeParent(parent CommandSpecificDataItem)
+       GetParent() *CommandSpecificDataItem
+
+       GetTypeName() string
+       CommandSpecificDataItem
+}
+
+// NewCommandSpecificDataItem factory function for _CommandSpecificDataItem
+func NewCommandSpecificDataItem() *_CommandSpecificDataItem {
+       return &_CommandSpecificDataItem{}
+}
+
+// Deprecated: use the interface for direct cast
+func CastCommandSpecificDataItem(structType any) CommandSpecificDataItem {
+       if casted, ok := structType.(CommandSpecificDataItem); ok {
+               return casted
+       }
+       if casted, ok := structType.(*CommandSpecificDataItem); ok {
+               return *casted
+       }
+       return nil
+}
+
+func (m *_CommandSpecificDataItem) GetTypeName() string {
+       return "CommandSpecificDataItem"
+}
+
+func (m *_CommandSpecificDataItem) GetParentLengthInBits(ctx context.Context) 
uint16 {
+       lengthInBits := uint16(0)
+       // Discriminator Field (itemType)
+       lengthInBits += 16
+
+       return lengthInBits
+}
+
+func (m *_CommandSpecificDataItem) GetLengthInBytes(ctx context.Context) 
uint16 {
+       return m.GetLengthInBits(ctx) / 8
+}
+
+func CommandSpecificDataItemParse(theBytes []byte) (CommandSpecificDataItem, 
error) {
+       return CommandSpecificDataItemParseWithBuffer(context.Background(), 
utils.NewReadBufferByteBased(theBytes))
+}
+
+func CommandSpecificDataItemParseWithBuffer(ctx context.Context, readBuffer 
utils.ReadBuffer) (CommandSpecificDataItem, error) {
+       positionAware := readBuffer
+       _ = positionAware
+       if pullErr := readBuffer.PullContext("CommandSpecificDataItem"); 
pullErr != nil {
+               return nil, errors.Wrap(pullErr, "Error pulling for 
CommandSpecificDataItem")
+       }
+       currentPos := positionAware.GetPos()
+       _ = currentPos
+
+       // Discriminator Field (itemType) (Used as input to a switch field)
+       itemType, _itemTypeErr := readBuffer.ReadUint16("itemType", 16)
+       if _itemTypeErr != nil {
+               return nil, errors.Wrap(_itemTypeErr, "Error parsing 'itemType' 
field of CommandSpecificDataItem")
+       }
+
+       // Switch Field (Depending on the discriminator values, passes the 
instantiation to a sub-type)
+       type CommandSpecificDataItemChildSerializeRequirement interface {
+               CommandSpecificDataItem
+               InitializeParent(CommandSpecificDataItem)
+               GetParent() CommandSpecificDataItem
+       }
+       var _childTemp any
+       var _child CommandSpecificDataItemChildSerializeRequirement
+       var typeSwitchError error
+       switch {
+       case itemType == 0x000C: // CipIdentity
+               _childTemp, typeSwitchError = CipIdentityParseWithBuffer(ctx, 
readBuffer)
+       case itemType == 0x0086: // CipSecurityInformation
+               _childTemp, typeSwitchError = 
CipSecurityInformationParseWithBuffer(ctx, readBuffer)
+       default:
+               typeSwitchError = errors.Errorf("Unmapped type for parameters 
[itemType=%v]", itemType)
+       }
+       if typeSwitchError != nil {
+               return nil, errors.Wrap(typeSwitchError, "Error parsing 
sub-type for type-switch of CommandSpecificDataItem")
+       }
+       _child = _childTemp.(CommandSpecificDataItemChildSerializeRequirement)
+
+       if closeErr := readBuffer.CloseContext("CommandSpecificDataItem"); 
closeErr != nil {
+               return nil, errors.Wrap(closeErr, "Error closing for 
CommandSpecificDataItem")
+       }
+
+       // Finish initializing
+       _child.InitializeParent(_child)
+       return _child, nil
+}
+
+func (pm *_CommandSpecificDataItem) SerializeParent(ctx context.Context, 
writeBuffer utils.WriteBuffer, child CommandSpecificDataItem, 
serializeChildFunction func() error) error {
+       // We redirect all calls through client as some methods are only 
implemented there
+       m := child
+       _ = m
+       positionAware := writeBuffer
+       _ = positionAware
+       if pushErr := writeBuffer.PushContext("CommandSpecificDataItem"); 
pushErr != nil {
+               return errors.Wrap(pushErr, "Error pushing for 
CommandSpecificDataItem")
+       }
+
+       // Discriminator Field (itemType) (Used as input to a switch field)
+       itemType := uint16(child.GetItemType())
+       _itemTypeErr := writeBuffer.WriteUint16("itemType", 16, (itemType))
+
+       if _itemTypeErr != nil {
+               return errors.Wrap(_itemTypeErr, "Error serializing 'itemType' 
field")
+       }
+
+       // Switch field (Depending on the discriminator values, passes the 
serialization to a sub-type)
+       if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
+               return errors.Wrap(_typeSwitchErr, "Error serializing sub-type 
field")
+       }
+
+       if popErr := writeBuffer.PopContext("CommandSpecificDataItem"); popErr 
!= nil {
+               return errors.Wrap(popErr, "Error popping for 
CommandSpecificDataItem")
+       }
+       return nil
+}
+
+func (m *_CommandSpecificDataItem) isCommandSpecificDataItem() bool {
+       return true
+}
+
+func (m *_CommandSpecificDataItem) String() string {
+       if m == nil {
+               return "<nil>"
+       }
+       writeBuffer := utils.NewWriteBufferBoxBasedWithOptions(true, true)
+       if err := writeBuffer.WriteSerializable(context.Background(), m); err 
!= nil {
+               return err.Error()
+       }
+       return writeBuffer.GetBox().String()
+}
diff --git a/plc4go/protocols/eip/readwrite/model/EipListIdentityRequest.go 
b/plc4go/protocols/eip/readwrite/model/EipListIdentityRequest.go
new file mode 100644
index 0000000000..0197eeadf3
--- /dev/null
+++ b/plc4go/protocols/eip/readwrite/model/EipListIdentityRequest.go
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package model
+
+import (
+       "context"
+       "fmt"
+       "github.com/apache/plc4x/plc4go/spi/utils"
+       "github.com/pkg/errors"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// EipListIdentityRequest is the corresponding interface of 
EipListIdentityRequest
+type EipListIdentityRequest interface {
+       fmt.Stringer
+       utils.LengthAware
+       utils.Serializable
+       EipPacket
+}
+
+// EipListIdentityRequestExactly can be used when we want exactly this type 
and not a type which fulfills EipListIdentityRequest.
+// This is useful for switch cases.
+type EipListIdentityRequestExactly interface {
+       EipListIdentityRequest
+       isEipListIdentityRequest() bool
+}
+
+// _EipListIdentityRequest is the data-structure of this message
+type _EipListIdentityRequest struct {
+       *_EipPacket
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for discriminator values.
+///////////////////////
+
+func (m *_EipListIdentityRequest) GetCommand() uint16 {
+       return 0x0063
+}
+
+func (m *_EipListIdentityRequest) GetResponse() bool {
+       return bool(false)
+}
+
+func (m *_EipListIdentityRequest) GetPacketLength() uint16 {
+       return 0
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+func (m *_EipListIdentityRequest) InitializeParent(parent EipPacket, 
sessionHandle uint32, status uint32, senderContext []byte, options uint32) {
+       m.SessionHandle = sessionHandle
+       m.Status = status
+       m.SenderContext = senderContext
+       m.Options = options
+}
+
+func (m *_EipListIdentityRequest) GetParent() EipPacket {
+       return m._EipPacket
+}
+
+// NewEipListIdentityRequest factory function for _EipListIdentityRequest
+func NewEipListIdentityRequest(sessionHandle uint32, status uint32, 
senderContext []byte, options uint32) *_EipListIdentityRequest {
+       _result := &_EipListIdentityRequest{
+               _EipPacket: NewEipPacket(sessionHandle, status, senderContext, 
options),
+       }
+       _result._EipPacket._EipPacketChildRequirements = _result
+       return _result
+}
+
+// Deprecated: use the interface for direct cast
+func CastEipListIdentityRequest(structType any) EipListIdentityRequest {
+       if casted, ok := structType.(EipListIdentityRequest); ok {
+               return casted
+       }
+       if casted, ok := structType.(*EipListIdentityRequest); ok {
+               return *casted
+       }
+       return nil
+}
+
+func (m *_EipListIdentityRequest) GetTypeName() string {
+       return "EipListIdentityRequest"
+}
+
+func (m *_EipListIdentityRequest) GetLengthInBits(ctx context.Context) uint16 {
+       lengthInBits := uint16(m.GetParentLengthInBits(ctx))
+
+       return lengthInBits
+}
+
+func (m *_EipListIdentityRequest) GetLengthInBytes(ctx context.Context) uint16 
{
+       return m.GetLengthInBits(ctx) / 8
+}
+
+func EipListIdentityRequestParse(theBytes []byte, response bool) 
(EipListIdentityRequest, error) {
+       return EipListIdentityRequestParseWithBuffer(context.Background(), 
utils.NewReadBufferByteBased(theBytes), response)
+}
+
+func EipListIdentityRequestParseWithBuffer(ctx context.Context, readBuffer 
utils.ReadBuffer, response bool) (EipListIdentityRequest, error) {
+       positionAware := readBuffer
+       _ = positionAware
+       if pullErr := readBuffer.PullContext("EipListIdentityRequest"); pullErr 
!= nil {
+               return nil, errors.Wrap(pullErr, "Error pulling for 
EipListIdentityRequest")
+       }
+       currentPos := positionAware.GetPos()
+       _ = currentPos
+
+       if closeErr := readBuffer.CloseContext("EipListIdentityRequest"); 
closeErr != nil {
+               return nil, errors.Wrap(closeErr, "Error closing for 
EipListIdentityRequest")
+       }
+
+       // Create a partially initialized instance
+       _child := &_EipListIdentityRequest{
+               _EipPacket: &_EipPacket{},
+       }
+       _child._EipPacket._EipPacketChildRequirements = _child
+       return _child, nil
+}
+
+func (m *_EipListIdentityRequest) Serialize() ([]byte, error) {
+       wb := 
utils.NewWriteBufferByteBased(utils.WithInitialSizeForByteBasedBuffer(int(m.GetLengthInBytes(context.Background()))))
+       if err := m.SerializeWithWriteBuffer(context.Background(), wb); err != 
nil {
+               return nil, err
+       }
+       return wb.GetBytes(), nil
+}
+
+func (m *_EipListIdentityRequest) SerializeWithWriteBuffer(ctx 
context.Context, writeBuffer utils.WriteBuffer) error {
+       positionAware := writeBuffer
+       _ = positionAware
+       ser := func() error {
+               if pushErr := 
writeBuffer.PushContext("EipListIdentityRequest"); pushErr != nil {
+                       return errors.Wrap(pushErr, "Error pushing for 
EipListIdentityRequest")
+               }
+
+               if popErr := writeBuffer.PopContext("EipListIdentityRequest"); 
popErr != nil {
+                       return errors.Wrap(popErr, "Error popping for 
EipListIdentityRequest")
+               }
+               return nil
+       }
+       return m.SerializeParent(ctx, writeBuffer, m, ser)
+}
+
+func (m *_EipListIdentityRequest) isEipListIdentityRequest() bool {
+       return true
+}
+
+func (m *_EipListIdentityRequest) String() string {
+       if m == nil {
+               return "<nil>"
+       }
+       writeBuffer := utils.NewWriteBufferBoxBasedWithOptions(true, true)
+       if err := writeBuffer.WriteSerializable(context.Background(), m); err 
!= nil {
+               return err.Error()
+       }
+       return writeBuffer.GetBox().String()
+}
diff --git a/plc4go/protocols/eip/readwrite/model/EipListIdentityResponse.go 
b/plc4go/protocols/eip/readwrite/model/EipListIdentityResponse.go
new file mode 100644
index 0000000000..71e7d38b85
--- /dev/null
+++ b/plc4go/protocols/eip/readwrite/model/EipListIdentityResponse.go
@@ -0,0 +1,270 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package model
+
+import (
+       "context"
+       "fmt"
+       "github.com/apache/plc4x/plc4go/spi/utils"
+       "github.com/pkg/errors"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// EipListIdentityResponse is the corresponding interface of 
EipListIdentityResponse
+type EipListIdentityResponse interface {
+       fmt.Stringer
+       utils.LengthAware
+       utils.Serializable
+       EipPacket
+       // GetItems returns Items (property field)
+       GetItems() []CommandSpecificDataItem
+}
+
+// EipListIdentityResponseExactly can be used when we want exactly this type 
and not a type which fulfills EipListIdentityResponse.
+// This is useful for switch cases.
+type EipListIdentityResponseExactly interface {
+       EipListIdentityResponse
+       isEipListIdentityResponse() bool
+}
+
+// _EipListIdentityResponse is the data-structure of this message
+type _EipListIdentityResponse struct {
+       *_EipPacket
+       Items []CommandSpecificDataItem
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for discriminator values.
+///////////////////////
+
+func (m *_EipListIdentityResponse) GetCommand() uint16 {
+       return 0x0063
+}
+
+func (m *_EipListIdentityResponse) GetResponse() bool {
+       return bool(true)
+}
+
+func (m *_EipListIdentityResponse) GetPacketLength() uint16 {
+       return 0
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+func (m *_EipListIdentityResponse) InitializeParent(parent EipPacket, 
sessionHandle uint32, status uint32, senderContext []byte, options uint32) {
+       m.SessionHandle = sessionHandle
+       m.Status = status
+       m.SenderContext = senderContext
+       m.Options = options
+}
+
+func (m *_EipListIdentityResponse) GetParent() EipPacket {
+       return m._EipPacket
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for property fields.
+///////////////////////
+
+func (m *_EipListIdentityResponse) GetItems() []CommandSpecificDataItem {
+       return m.Items
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+// NewEipListIdentityResponse factory function for _EipListIdentityResponse
+func NewEipListIdentityResponse(items []CommandSpecificDataItem, sessionHandle 
uint32, status uint32, senderContext []byte, options uint32) 
*_EipListIdentityResponse {
+       _result := &_EipListIdentityResponse{
+               Items:      items,
+               _EipPacket: NewEipPacket(sessionHandle, status, senderContext, 
options),
+       }
+       _result._EipPacket._EipPacketChildRequirements = _result
+       return _result
+}
+
+// Deprecated: use the interface for direct cast
+func CastEipListIdentityResponse(structType any) EipListIdentityResponse {
+       if casted, ok := structType.(EipListIdentityResponse); ok {
+               return casted
+       }
+       if casted, ok := structType.(*EipListIdentityResponse); ok {
+               return *casted
+       }
+       return nil
+}
+
+func (m *_EipListIdentityResponse) GetTypeName() string {
+       return "EipListIdentityResponse"
+}
+
+func (m *_EipListIdentityResponse) GetLengthInBits(ctx context.Context) uint16 
{
+       lengthInBits := uint16(m.GetParentLengthInBits(ctx))
+
+       // Implicit Field (itemCount)
+       lengthInBits += 16
+
+       // Array field
+       if len(m.Items) > 0 {
+               for _curItem, element := range m.Items {
+                       arrayCtx := utils.CreateArrayContext(ctx, len(m.Items), 
_curItem)
+                       _ = arrayCtx
+                       _ = _curItem
+                       lengthInBits += element.(interface{ 
GetLengthInBits(context.Context) uint16 }).GetLengthInBits(arrayCtx)
+               }
+       }
+
+       return lengthInBits
+}
+
+func (m *_EipListIdentityResponse) GetLengthInBytes(ctx context.Context) 
uint16 {
+       return m.GetLengthInBits(ctx) / 8
+}
+
+func EipListIdentityResponseParse(theBytes []byte, response bool) 
(EipListIdentityResponse, error) {
+       return EipListIdentityResponseParseWithBuffer(context.Background(), 
utils.NewReadBufferByteBased(theBytes), response)
+}
+
+func EipListIdentityResponseParseWithBuffer(ctx context.Context, readBuffer 
utils.ReadBuffer, response bool) (EipListIdentityResponse, error) {
+       positionAware := readBuffer
+       _ = positionAware
+       if pullErr := readBuffer.PullContext("EipListIdentityResponse"); 
pullErr != nil {
+               return nil, errors.Wrap(pullErr, "Error pulling for 
EipListIdentityResponse")
+       }
+       currentPos := positionAware.GetPos()
+       _ = currentPos
+
+       // Implicit Field (itemCount) (Used for parsing, but its value is not 
stored as it's implicitly given by the objects content)
+       itemCount, _itemCountErr := readBuffer.ReadUint16("itemCount", 16)
+       _ = itemCount
+       if _itemCountErr != nil {
+               return nil, errors.Wrap(_itemCountErr, "Error parsing 
'itemCount' field of EipListIdentityResponse")
+       }
+
+       // Array field (items)
+       if pullErr := readBuffer.PullContext("items", 
utils.WithRenderAsList(true)); pullErr != nil {
+               return nil, errors.Wrap(pullErr, "Error pulling for items")
+       }
+       // Count array
+       items := make([]CommandSpecificDataItem, itemCount)
+       // This happens when the size is set conditional to 0
+       if len(items) == 0 {
+               items = nil
+       }
+       {
+               _numItems := uint16(itemCount)
+               for _curItem := uint16(0); _curItem < _numItems; _curItem++ {
+                       arrayCtx := utils.CreateArrayContext(ctx, 
int(_numItems), int(_curItem))
+                       _ = arrayCtx
+                       _ = _curItem
+                       _item, _err := 
CommandSpecificDataItemParseWithBuffer(arrayCtx, readBuffer)
+                       if _err != nil {
+                               return nil, errors.Wrap(_err, "Error parsing 
'items' field of EipListIdentityResponse")
+                       }
+                       items[_curItem] = _item.(CommandSpecificDataItem)
+               }
+       }
+       if closeErr := readBuffer.CloseContext("items", 
utils.WithRenderAsList(true)); closeErr != nil {
+               return nil, errors.Wrap(closeErr, "Error closing for items")
+       }
+
+       if closeErr := readBuffer.CloseContext("EipListIdentityResponse"); 
closeErr != nil {
+               return nil, errors.Wrap(closeErr, "Error closing for 
EipListIdentityResponse")
+       }
+
+       // Create a partially initialized instance
+       _child := &_EipListIdentityResponse{
+               _EipPacket: &_EipPacket{},
+               Items:      items,
+       }
+       _child._EipPacket._EipPacketChildRequirements = _child
+       return _child, nil
+}
+
+func (m *_EipListIdentityResponse) Serialize() ([]byte, error) {
+       wb := 
utils.NewWriteBufferByteBased(utils.WithInitialSizeForByteBasedBuffer(int(m.GetLengthInBytes(context.Background()))))
+       if err := m.SerializeWithWriteBuffer(context.Background(), wb); err != 
nil {
+               return nil, err
+       }
+       return wb.GetBytes(), nil
+}
+
+func (m *_EipListIdentityResponse) SerializeWithWriteBuffer(ctx 
context.Context, writeBuffer utils.WriteBuffer) error {
+       positionAware := writeBuffer
+       _ = positionAware
+       ser := func() error {
+               if pushErr := 
writeBuffer.PushContext("EipListIdentityResponse"); pushErr != nil {
+                       return errors.Wrap(pushErr, "Error pushing for 
EipListIdentityResponse")
+               }
+
+               // Implicit Field (itemCount) (Used for parsing, but it's value 
is not stored as it's implicitly given by the objects content)
+               itemCount := uint16(uint16(len(m.GetItems())))
+               _itemCountErr := writeBuffer.WriteUint16("itemCount", 16, 
(itemCount))
+               if _itemCountErr != nil {
+                       return errors.Wrap(_itemCountErr, "Error serializing 
'itemCount' field")
+               }
+
+               // Array Field (items)
+               if pushErr := writeBuffer.PushContext("items", 
utils.WithRenderAsList(true)); pushErr != nil {
+                       return errors.Wrap(pushErr, "Error pushing for items")
+               }
+               for _curItem, _element := range m.GetItems() {
+                       _ = _curItem
+                       arrayCtx := utils.CreateArrayContext(ctx, 
len(m.GetItems()), _curItem)
+                       _ = arrayCtx
+                       _elementErr := writeBuffer.WriteSerializable(arrayCtx, 
_element)
+                       if _elementErr != nil {
+                               return errors.Wrap(_elementErr, "Error 
serializing 'items' field")
+                       }
+               }
+               if popErr := writeBuffer.PopContext("items", 
utils.WithRenderAsList(true)); popErr != nil {
+                       return errors.Wrap(popErr, "Error popping for items")
+               }
+
+               if popErr := writeBuffer.PopContext("EipListIdentityResponse"); 
popErr != nil {
+                       return errors.Wrap(popErr, "Error popping for 
EipListIdentityResponse")
+               }
+               return nil
+       }
+       return m.SerializeParent(ctx, writeBuffer, m, ser)
+}
+
+func (m *_EipListIdentityResponse) isEipListIdentityResponse() bool {
+       return true
+}
+
+func (m *_EipListIdentityResponse) String() string {
+       if m == nil {
+               return "<nil>"
+       }
+       writeBuffer := utils.NewWriteBufferBoxBasedWithOptions(true, true)
+       if err := writeBuffer.WriteSerializable(context.Background(), m); err 
!= nil {
+               return err.Error()
+       }
+       return writeBuffer.GetBox().String()
+}
diff --git 
a/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/DceRpc_Packet.java
 
b/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/DceRpc_Packet.java
index fba7a81c69..bea66c6550 100644
--- 
a/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/DceRpc_Packet.java
+++ 
b/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/DceRpc_Packet.java
@@ -49,7 +49,6 @@ public class DceRpc_Packet implements Message {
   public static final Integer ACTIVITYHINT = 0xFFFF;
   public static final Integer FRAGMENTNUM = 0x0000;
   public static final Short AUTHPROTO = 0x00;
-  public static final Short SERIALLOW = 0x00;
 
   // Properties.
   protected final DceRpc_PacketType packetType;
@@ -65,6 +64,7 @@ public class DceRpc_Packet implements Message {
   protected final long serverBootTime;
   protected final long sequenceNumber;
   protected final DceRpc_Operation operation;
+  protected final short serialLow;
   protected final PnIoCm_Packet payload;
 
   // Reserved Fields
@@ -88,6 +88,7 @@ public class DceRpc_Packet implements Message {
       long serverBootTime,
       long sequenceNumber,
       DceRpc_Operation operation,
+      short serialLow,
       PnIoCm_Packet payload) {
     super();
     this.packetType = packetType;
@@ -103,6 +104,7 @@ public class DceRpc_Packet implements Message {
     this.serverBootTime = serverBootTime;
     this.sequenceNumber = sequenceNumber;
     this.operation = operation;
+    this.serialLow = serialLow;
     this.payload = payload;
   }
 
@@ -158,6 +160,10 @@ public class DceRpc_Packet implements Message {
     return operation;
   }
 
+  public short getSerialLow() {
+    return serialLow;
+  }
+
   public PnIoCm_Packet getPayload() {
     return payload;
   }
@@ -206,10 +212,6 @@ public class DceRpc_Packet implements Message {
     return AUTHPROTO;
   }
 
-  public short getSerialLow() {
-    return SERIALLOW;
-  }
-
   public void serialize(WriteBuffer writeBuffer) throws SerializationException 
{
     PositionAware positionAware = writeBuffer;
     boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
@@ -476,10 +478,10 @@ public class DceRpc_Packet implements Message {
                 ? ByteOrder.BIG_ENDIAN
                 : ByteOrder.LITTLE_ENDIAN)));
 
-    // Const Field (serialLow)
-    writeConstField(
+    // Simple Field (serialLow)
+    writeSimpleField(
         "serialLow",
-        SERIALLOW,
+        serialLow,
         writeUnsignedShort(writeBuffer, 8),
         WithOption.WithByteOrder(ByteOrder.BIG_ENDIAN));
 
@@ -597,7 +599,7 @@ public class DceRpc_Packet implements Message {
     // Const Field (authProto)
     lengthInBits += 8;
 
-    // Const Field (serialLow)
+    // Simple field (serialLow)
     lengthInBits += 8;
 
     // Simple field (payload)
@@ -861,10 +863,9 @@ public class DceRpc_Packet implements Message {
                     : ByteOrder.LITTLE_ENDIAN)));
 
     short serialLow =
-        readConstField(
+        readSimpleField(
             "serialLow",
             readUnsignedShort(readBuffer, 8),
-            DceRpc_Packet.SERIALLOW,
             WithOption.WithByteOrder(ByteOrder.BIG_ENDIAN));
 
     PnIoCm_Packet payload =
@@ -896,6 +897,7 @@ public class DceRpc_Packet implements Message {
             serverBootTime,
             sequenceNumber,
             operation,
+            serialLow,
             payload);
     _dceRpc_Packet.reservedField0 = reservedField0;
     _dceRpc_Packet.reservedField1 = reservedField1;
@@ -927,6 +929,7 @@ public class DceRpc_Packet implements Message {
         && (getServerBootTime() == that.getServerBootTime())
         && (getSequenceNumber() == that.getSequenceNumber())
         && (getOperation() == that.getOperation())
+        && (getSerialLow() == that.getSerialLow())
         && (getPayload() == that.getPayload())
         && true;
   }
@@ -947,6 +950,7 @@ public class DceRpc_Packet implements Message {
         getServerBootTime(),
         getSequenceNumber(),
         getOperation(),
+        getSerialLow(),
         getPayload());
   }
 
diff --git 
a/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Packet.java
 
b/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Packet.java
index 5d80b35886..7ede523d3d 100644
--- 
a/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Packet.java
+++ 
b/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Packet.java
@@ -115,6 +115,8 @@ public abstract class PnIoCm_Packet implements Message {
       builder = 
PnIoCm_Packet_NoCall.staticParsePnIoCm_PacketBuilder(readBuffer, packetType);
     } else if (EvaluationHelper.equals(packetType, DceRpc_PacketType.REJECT)) {
       builder = PnIoCm_Packet_Rej.staticParsePnIoCm_PacketBuilder(readBuffer, 
packetType);
+    } else if (EvaluationHelper.equals(packetType, DceRpc_PacketType.WORKING)) 
{
+      builder = 
PnIoCm_Packet_Working.staticParsePnIoCm_PacketBuilder(readBuffer, packetType);
     }
     if (builder == null) {
       throw new ParseException(
diff --git 
a/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Packet_Working.java
 
b/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Packet_Working.java
new file mode 100644
index 0000000000..9384c89322
--- /dev/null
+++ 
b/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Packet_Working.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.plc4x.java.profinet.readwrite;
+
+import static org.apache.plc4x.java.spi.codegen.fields.FieldReaderFactory.*;
+import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*;
+import static org.apache.plc4x.java.spi.codegen.io.DataReaderFactory.*;
+import static org.apache.plc4x.java.spi.codegen.io.DataWriterFactory.*;
+import static org.apache.plc4x.java.spi.generation.StaticHelper.*;
+
+import java.time.*;
+import java.util.*;
+import org.apache.plc4x.java.api.exceptions.*;
+import org.apache.plc4x.java.api.value.*;
+import org.apache.plc4x.java.spi.codegen.*;
+import org.apache.plc4x.java.spi.codegen.fields.*;
+import org.apache.plc4x.java.spi.codegen.io.*;
+import org.apache.plc4x.java.spi.generation.*;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+public class PnIoCm_Packet_Working extends PnIoCm_Packet implements Message {
+
+  // Accessors for discriminator values.
+  public DceRpc_PacketType getPacketType() {
+    return DceRpc_PacketType.WORKING;
+  }
+
+  public PnIoCm_Packet_Working() {
+    super();
+  }
+
+  @Override
+  protected void serializePnIoCm_PacketChild(WriteBuffer writeBuffer)
+      throws SerializationException {
+    PositionAware positionAware = writeBuffer;
+    boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+    writeBuffer.pushContext("PnIoCm_Packet_Working");
+
+    writeBuffer.popContext("PnIoCm_Packet_Working");
+  }
+
+  @Override
+  public int getLengthInBytes() {
+    return (int) Math.ceil((float) getLengthInBits() / 8.0);
+  }
+
+  @Override
+  public int getLengthInBits() {
+    int lengthInBits = super.getLengthInBits();
+    PnIoCm_Packet_Working _value = this;
+    boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+
+    return lengthInBits;
+  }
+
+  public static PnIoCm_PacketBuilder staticParsePnIoCm_PacketBuilder(
+      ReadBuffer readBuffer, DceRpc_PacketType packetType) throws 
ParseException {
+    readBuffer.pullContext("PnIoCm_Packet_Working");
+    PositionAware positionAware = readBuffer;
+    boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+
+    readBuffer.closeContext("PnIoCm_Packet_Working");
+    // Create the instance
+    return new PnIoCm_Packet_WorkingBuilderImpl();
+  }
+
+  public static class PnIoCm_Packet_WorkingBuilderImpl
+      implements PnIoCm_Packet.PnIoCm_PacketBuilder {
+
+    public PnIoCm_Packet_WorkingBuilderImpl() {}
+
+    public PnIoCm_Packet_Working build() {
+      PnIoCm_Packet_Working pnIoCm_Packet_Working = new 
PnIoCm_Packet_Working();
+      return pnIoCm_Packet_Working;
+    }
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof PnIoCm_Packet_Working)) {
+      return false;
+    }
+    PnIoCm_Packet_Working that = (PnIoCm_Packet_Working) o;
+    return super.equals(that) && true;
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(super.hashCode());
+  }
+
+  @Override
+  public String toString() {
+    WriteBufferBoxBased writeBufferBoxBased = new WriteBufferBoxBased(true, 
true);
+    try {
+      writeBufferBoxBased.writeSerializable(this);
+    } catch (SerializationException e) {
+      throw new RuntimeException(e);
+    }
+    return "\n" + writeBufferBoxBased.getBox().toString() + "\n";
+  }
+}
diff --git 
a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/device/ProfinetChannel.java
 
b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/device/ProfinetChannel.java
index d9ed9f0db2..01a87ff3d1 100644
--- 
a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/device/ProfinetChannel.java
+++ 
b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/device/ProfinetChannel.java
@@ -138,7 +138,9 @@ public class ProfinetChannel {
                                     }
                                     else if (pdu.getFrameId() == 
PnDcp_FrameId.RT_CLASS_1) {
                                         for (Map.Entry<String, ProfinetDevice> 
device : devices.entrySet()) {
-                                            if 
(Arrays.equals(device.getValue().getDeviceContext().getMacAddress().getAddress(),
 ethernetFrame.getSource().getAddress())) {
+                                            if 
(device.getValue().getDeviceContext().getMacAddress() == null) {
+                                                logger.info("Hurz");
+                                            } else if 
(Arrays.equals(device.getValue().getDeviceContext().getMacAddress().getAddress(),
 ethernetFrame.getSource().getAddress())) {
                                                 PnDcp_Pdu_RealTimeCyclic 
cyclicPdu = (PnDcp_Pdu_RealTimeCyclic) pdu;
                                                 
device.getValue().handleRealTimeResponse(cyclicPdu);
                                             }
@@ -150,9 +152,30 @@ public class ProfinetChannel {
                                     discoverer.processLldp(pdu);
                                 }
                             } else if (payload instanceof 
Ethernet_FramePayload_IPv4) {
-                                for (Map.Entry<String, ProfinetDevice> device 
: devices.entrySet()) {
-                                    if 
(Arrays.equals(device.getValue().getDeviceContext().getMacAddress().getAddress(),
 ethernetFrame.getSource().getAddress())) {
-                                        
device.getValue().handleResponse((Ethernet_FramePayload_IPv4) payload);
+                                Ethernet_FramePayload_IPv4 payloadIPv4 = 
(Ethernet_FramePayload_IPv4) payload;
+                                if (payloadIPv4.getPayload().getPacketType() 
== DceRpc_PacketType.PING) {
+                                    DceRpc_Packet pingRequest = 
payloadIPv4.getPayload();
+                                    // Intercept ping packets that originated 
from the PN device itself.
+                                    // TODO: Find out how to react to PING 
messages.
+                                    // According to 
https://pubs.opengroup.org/onlinepubs/9629399/chap12.htm the correct response 
for us to such a ping message would be a "working" response
+                                    Ethernet_Frame pingResponse = new 
Ethernet_Frame(ethernetFrame.getSource(), ethernetFrame.getDestination(),
+                                        new 
Ethernet_FramePayload_IPv4(payloadIPv4.getIdentification(), false, false,
+                                            payloadIPv4.getTimeToLive(), 
payloadIPv4.getDestinationAddress(),
+                                            payloadIPv4.getSourceAddress(), 
payloadIPv4.getDestinationPort(),
+                                            payloadIPv4.getSourcePort(), new 
DceRpc_Packet(DceRpc_PacketType.WORKING,
+                                            false, false, false,
+                                            IntegerEncoding.BIG_ENDIAN, 
CharacterEncoding.ASCII, FloatingPointEncoding.IEEE,
+                                            pingRequest.getObjectUuid(), 
pingRequest.getInterfaceUuid(), pingRequest.getActivityUuid(),
+                                            0L, 0L, DceRpc_Operation.CONNECT, 
(short) 0, new PnIoCm_Packet_Working())
+                                            ));
+                                    this.send(pingResponse);
+
+                                    logger.info("Received PING packet: {}", 
packet);
+                                } else {
+                                    for (Map.Entry<String, ProfinetDevice> 
device : devices.entrySet()) {
+                                        if 
(Arrays.equals(device.getValue().getDeviceContext().getMacAddress().getAddress(),
 ethernetFrame.getSource().getAddress())) {
+                                            
device.getValue().handleResponse(payloadIPv4);
+                                        }
                                     }
                                 }
                             }
diff --git 
a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/device/ProfinetDevice.java
 
b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/device/ProfinetDevice.java
index 5b12a524a0..e05df3b958 100644
--- 
a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/device/ProfinetDevice.java
+++ 
b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/device/ProfinetDevice.java
@@ -596,6 +596,7 @@ public class ProfinetDevice implements PlcSubscriber {
                 0,
                 id,
                 DceRpc_Operation.CONNECT,
+                (short) 0,
                 new 
PnIoCm_Packet_Req(ProfinetDeviceContext.DEFAULT_ARGS_MAXIMUM, 
ProfinetDeviceContext.DEFAULT_MAX_ARRAY_COUNT, 0, blocks)
             );
         }
@@ -738,6 +739,7 @@ public class ProfinetDevice implements PlcSubscriber {
                 0,
                 id,
                 DceRpc_Operation.WRITE,
+                (short) 0,
                 new PnIoCm_Packet_Req(16696, 16696, 0,
                     requests)
             );
@@ -798,6 +800,7 @@ public class ProfinetDevice implements PlcSubscriber {
                 0,
                 id,
                 DceRpc_Operation.CONTROL,
+                (short) 0,
                 new PnIoCm_Packet_Req(16696, 16696, 0,
                     Collections.singletonList(
                         new PnIoCm_Control_Request(
@@ -873,6 +876,7 @@ public class ProfinetDevice implements PlcSubscriber {
                 0,
                 id,
                 DceRpc_Operation.CONTROL,
+                (short) 0,
                 new PnIoCm_Packet_Res(
                     (short) 0,
                     (short) 0,
@@ -932,6 +936,7 @@ public class ProfinetDevice implements PlcSubscriber {
                 0,
                 id,
                 DceRpc_Operation.CONTROL,
+                (short) 0,
                 new PnIoCm_Packet_NoCall()
             );
         }
diff --git 
a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java
 
b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java
index e7b414a662..84b95a2196 100644
--- 
a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java
+++ 
b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java
@@ -393,6 +393,7 @@ public class ProfinetPlcDiscoverer implements PlcDiscoverer 
{
                                         new TlvManagementAddress(
                                             12,
                                             ManagementAddressSubType.IPV4,
+                                            // 192.168.90.110
                                             new 
IpAddress(Hex.decodeHex("c0a85a6e")),
                                             (short) 0x03,
                                             0x01L,
diff --git 
a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetProtocolLogic.java
 
b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetProtocolLogic.java
index 44e7ff4b2f..05697cada1 100644
--- 
a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetProtocolLogic.java
+++ 
b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetProtocolLogic.java
@@ -130,15 +130,24 @@ public class ProfinetProtocolLogic extends 
Plc4xProtocolBase<Ethernet_Frame> imp
         boolean discovered = false;
         int count = 0;
         while (!discovered) {
+            List<ProfinetDevice> missingDevices = new ArrayList<>();
             discovered = true;
-            // Check for each device, if there was an incoming response for an 
LLDP or DCP search request.
+            // Check for each device, if there was an incoming response for an 
LLDP and DCP search request.
+            // It seems that we need information from both the LLDP and the 
DCP response, so we need
+            // to check if both have been received.
             for (Map.Entry<String, ProfinetDevice> device : 
devices.entrySet()) {
                 if (!device.getValue().hasLldpPdu() || 
!device.getValue().hasDcpPdu()) {
                     discovered = false;
+                    missingDevices.add(device.getValue());
                 }
             }
             // If we've come past this more than 5 times (15 seconds), give up.
             if (count > 5) {
+                for (ProfinetDevice missingDevice : missingDevices) {
+                    if(missingDevice.hasDcpPdu() && 
!missingDevice.hasLldpPdu()) {
+                        LOGGER.info("- For device {} we only managed to get a 
DCP discovery response, is the device possibly not connected via an LLDP 
enables switch?", missingDevice.getDeviceId());
+                    }
+                }
                 throw new PlcConnectionException("One device failed to respond 
to discovery packet");
             }
             // If at least one device hasn't responded yet, we'll wait for 3 
more seconds and then check again.
diff --git 
a/plc4j/drivers/profinet/src/test/java/org/apache/plc4x/java/profinet/ManualProfinetIoTest.java
 
b/plc4j/drivers/profinet/src/test/java/org/apache/plc4x/java/profinet/ManualProfinetIoTest.java
index 082b4e27de..9e5b0784cf 100644
--- 
a/plc4j/drivers/profinet/src/test/java/org/apache/plc4x/java/profinet/ManualProfinetIoTest.java
+++ 
b/plc4j/drivers/profinet/src/test/java/org/apache/plc4x/java/profinet/ManualProfinetIoTest.java
@@ -39,16 +39,16 @@ public class ManualProfinetIoTest {
         //final PlcConnection connection = new 
DefaultPlcDriverManager().getConnection("profinet://192.168.54.2?gsddirectory=~/.gsd&devices=[[simocodexbpn156e,DAP%201,(1,),192.168.54.23]]&reductionratio=16&sendclockfactor=32&dataholdfactor=3&watchdogfactor=3");
         // REMARK: The driver would use the local network device with the 
given IP address and to an auto-discovery, trying to find any devices returned 
with the matching name.
         // If this device is then found and an IP address is provided, it 
would use PN-DCP to set the IP address of that device to the given value.
-        final PlcConnection connection = new 
DefaultPlcDriverManager().getConnection("profinet://192.168.24.220?gsddirectory=~/.gsd&devices=[[simocodexbpn156e,DAP%201,(1,),192.168.24.31]]&reductionratio=16&sendclockfactor=32&dataholdfactor=3&watchdogfactor=3");
+        final PlcConnection connection = new 
DefaultPlcDriverManager().getConnection("profinet://192.168.24.220?gsddirectory=~/.gsd&devices=[[cdxb195b3,DAP%201,(1,)]]&reductionratio=16&sendclockfactor=32&dataholdfactor=3&watchdogfactor=3");
         // Wireshark filters:
         // - S7 1200: eth.addr == 001c0605bcdc
         // - Simocode: eth.addr == 883f990006ef
         // - Adam Analog Input: eth.addr == 74fe4863f6c2
         // - Adam Digital I/O: eth.addr == 74fe48824a7c
-        PlcBrowseRequest browseRequest = 
connection.browseRequestBuilder().addQuery("Browse", "").build();
-        final PlcBrowseResponse browseResponse = browseRequest.execute().get();
+        //PlcBrowseRequest browseRequest = 
connection.browseRequestBuilder().addQuery("Browse", "").build();
+        //final PlcBrowseResponse browseResponse = 
browseRequest.execute().get();
         PlcSubscriptionRequest.Builder builder = 
connection.subscriptionRequestBuilder();
-        builder.addChangeOfStateTag("Input 4", 
ProfinetTag.of("simocodexbpn156e.1.1.Inputs.2:BOOL"));
+        builder.addChangeOfStateTag("Input 4", 
ProfinetTag.of("cdxb195b3.1.1.Inputs.2:BOOL"));
         PlcSubscriptionRequest request = builder.build();
 
         final PlcSubscriptionResponse response = request.execute().get();
diff --git 
a/plc4j/drivers/profinet/src/test/java/org/apache/plc4x/java/profinet/ProfinetCheckSumTests.java
 
b/plc4j/drivers/profinet/src/test/java/org/apache/plc4x/java/profinet/ProfinetCheckSumTests.java
index 8eef7cbc66..7fe7bbf652 100644
--- 
a/plc4j/drivers/profinet/src/test/java/org/apache/plc4x/java/profinet/ProfinetCheckSumTests.java
+++ 
b/plc4j/drivers/profinet/src/test/java/org/apache/plc4x/java/profinet/ProfinetCheckSumTests.java
@@ -49,6 +49,7 @@ public class ProfinetCheckSumTests {
             0,
             0,
             DceRpc_Operation.CONNECT,
+            (short) 0,
             new PnIoCm_Packet_Req(
                 16696,
                 16696,
diff --git 
a/protocols/profinet/src/main/resources/protocols/profinet/dcerpc.mspec 
b/protocols/profinet/src/main/resources/protocols/profinet/dcerpc.mspec
index bed0d5c9bb..53064f2ac8 100644
--- a/protocols/profinet/src/main/resources/protocols/profinet/dcerpc.mspec
+++ b/protocols/profinet/src/main/resources/protocols/profinet/dcerpc.mspec
@@ -73,7 +73,8 @@
         [const        uint 8             authProto                      0x00   
              ]
     ]
     // RPCSerialLow 4.10.3.2.7
-    [const            uint 8             serialLow                      0x00   
              ]
+    // REMARK: In general this would be a constant value of 0, but it seems 
that the PN device sends back PING packets which have non 0 values.
+    [simple           uint 8             serialLow                             
              ]
 // RPC Header }
 // RPC Payload {
     [simple PnIoCm_Packet('packetType') payload byteOrder='integerEncoding == 
IntegerEncoding.BIG_ENDIAN ? BIG_ENDIAN : LITTLE_ENDIAN' ]
diff --git 
a/protocols/profinet/src/main/resources/protocols/profinet/pnio.mspec 
b/protocols/profinet/src/main/resources/protocols/profinet/pnio.mspec
index d693830581..91e527e71b 100644
--- a/protocols/profinet/src/main/resources/protocols/profinet/pnio.mspec
+++ b/protocols/profinet/src/main/resources/protocols/profinet/pnio.mspec
@@ -59,6 +59,8 @@
         ['REJECT'   PnIoCm_Packet_Rej
             [simple uint 32      status                               ]
         ]
+        ['WORKING'  PnIoCm_Packet_Working
+        ]
     ]
 ]
 

Reply via email to