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 + ] ] ]
