You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2023/05/31 13:02:49 UTC

[plc4x] branch chore/profinet-phase-3 created (now 95a8648d03)

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

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


      at 95a8648d03 chore(plc4j/profinet): Tried adjusting the code to provide more help in error messages and started working on handling the "ping" messages.

This branch includes the following new commits:

     new 95a8648d03 chore(plc4j/profinet): Tried adjusting the code to provide more help in error messages and started working on handling the "ping" messages.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[plc4x] 01/01: chore(plc4j/profinet): Tried adjusting the code to provide more help in error messages and started working on handling the "ping" messages.

Posted by cd...@apache.org.
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 <cd...@apache.org>
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
+        ]
     ]
 ]