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/06/11 10:29:00 UTC

[plc4x] branch chore/profinet-phase-3 updated (a9aa5b8fc4 -> 67ed07a983)

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


    from a9aa5b8fc4 chore(plc4j/profinet-ng):  - Implemented the types needed to read "RealIdentifictionData" from the Device.  - Updated the connection process to use the information from that instead of the I&M0 data.  - Implemented the browse functionality.  - Documented the things I found out.
     new ee0db37493 chore(plc4j/profinet):  - Added some more comments
     new 67ed07a983 chore(plc4j/profinet-ng):  - Changed the ProfinetDriverContext to no longer contain the raw device profile data, but pre-processed structures based on slot and subslot.  - Simplified the browse logic  - Started implementing the subscription logic  - Added an empty dummy for PnIoCm_Block_ReqPluginAlarmApplicationReady as it seems that this is sent from the remote devices

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


Summary of changes:
 .../java/profinet/readwrite/PnIoCm_Block.java      |   4 +
 ...IoCm_Block_ReqPluginAlarmApplicationReady.java} |  48 ++--
 .../profinet/context/ProfinetDriverContext.java    |  40 ++--
 .../java/profinet/gsdml/ProfinetDataItem.java      |   4 +
 .../profinet/protocol/ProfinetProtocolLogic.java   | 259 ++++++++++++---------
 .../profinet/utils/ProfinetDataTypeMapper.java     |   6 +-
 .../java/profinet/readwrite/PnIoCm_Block.java      |   4 +
 ...IoCm_Block_ReqPluginAlarmApplicationReady.java} |  48 ++--
 .../plc4x/java/profinet/device/ProfinetDevice.java |  18 +-
 .../java/profinet/device/ProfinetModuleImpl.java   |   2 +
 .../plc4x/java/profinet/ManualProfinetIoTest.java  |   3 -
 .../main/resources/protocols/profinet/pnio.mspec   |   3 +
 12 files changed, 241 insertions(+), 198 deletions(-)
 copy plc4j/drivers/profinet-ng/src/main/generated/org/apache/plc4x/java/profinet/readwrite/{PnDcp_Block_DevicePropertiesStandardGateway.java => PnIoCm_Block_ReqPluginAlarmApplicationReady.java} (64%)
 copy plc4j/drivers/{profinet-ng/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnDcp_Block_DevicePropertiesStandardGateway.java => profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Block_ReqPluginAlarmApplicationReady.java} (64%)


[plc4x] 02/02: chore(plc4j/profinet-ng): - Changed the ProfinetDriverContext to no longer contain the raw device profile data, but pre-processed structures based on slot and subslot. - Simplified the browse logic - Started implementing the subscription logic - Added an empty dummy for PnIoCm_Block_ReqPluginAlarmApplicationReady as it seems that this is sent from the remote devices

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 67ed07a98381d5cba823a6d7afe9234e0e7a7f8e
Author: Christofer Dutz <cd...@apache.org>
AuthorDate: Sun Jun 11 12:07:56 2023 +0200

    chore(plc4j/profinet-ng):
     - Changed the ProfinetDriverContext to no longer contain the raw device profile data, but pre-processed structures based on slot and subslot.
     - Simplified the browse logic
     - Started implementing the subscription logic
     - Added an empty dummy for PnIoCm_Block_ReqPluginAlarmApplicationReady as it seems that this is sent from the remote devices
---
 .../java/profinet/readwrite/PnIoCm_Block.java      |   4 +
 ...nIoCm_Block_ReqPluginAlarmApplicationReady.java | 123 ++++++++++
 .../profinet/context/ProfinetDriverContext.java    |  40 ++--
 .../java/profinet/gsdml/ProfinetDataItem.java      |   4 +
 .../profinet/protocol/ProfinetProtocolLogic.java   | 259 ++++++++++++---------
 .../profinet/utils/ProfinetDataTypeMapper.java     |   6 +-
 .../java/profinet/readwrite/PnIoCm_Block.java      |   4 +
 ...nIoCm_Block_ReqPluginAlarmApplicationReady.java | 123 ++++++++++
 .../main/resources/protocols/profinet/pnio.mspec   |   3 +
 9 files changed, 432 insertions(+), 134 deletions(-)

diff --git a/plc4j/drivers/profinet-ng/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Block.java b/plc4j/drivers/profinet-ng/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Block.java
index e4bf5c8538..4065b85537 100644
--- a/plc4j/drivers/profinet-ng/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Block.java
+++ b/plc4j/drivers/profinet-ng/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Block.java
@@ -149,6 +149,10 @@ public abstract class PnIoCm_Block implements Message {
       builder = PnIoCm_Block_ArServer.staticParsePnIoCm_BlockBuilder(readBuffer);
     } else if (EvaluationHelper.equals(blockType, PnIoCm_BlockType.REAL_IDENTIFICATION_DATA)) {
       builder = PnIoCm_Block_RealIdentificationData.staticParsePnIoCm_BlockBuilder(readBuffer);
+    } else if (EvaluationHelper.equals(
+        blockType, PnIoCm_BlockType.IOD_BLOCK_REQ_PLUGIN_ALARM_APPLICATION_READY)) {
+      builder =
+          PnIoCm_Block_ReqPluginAlarmApplicationReady.staticParsePnIoCm_BlockBuilder(readBuffer);
     } else if (EvaluationHelper.equals(blockType, PnIoCm_BlockType.I_AND_M_0)) {
       builder = PnIoCm_Block_IAndM0.staticParsePnIoCm_BlockBuilder(readBuffer);
     } else if (EvaluationHelper.equals(blockType, PnIoCm_BlockType.I_AND_M_1)) {
diff --git a/plc4j/drivers/profinet-ng/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Block_ReqPluginAlarmApplicationReady.java b/plc4j/drivers/profinet-ng/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Block_ReqPluginAlarmApplicationReady.java
new file mode 100644
index 0000000000..73b9d230c4
--- /dev/null
+++ b/plc4j/drivers/profinet-ng/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Block_ReqPluginAlarmApplicationReady.java
@@ -0,0 +1,123 @@
+/*
+ * 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_Block_ReqPluginAlarmApplicationReady extends PnIoCm_Block implements Message {
+
+  // Accessors for discriminator values.
+  public PnIoCm_BlockType getBlockType() {
+    return PnIoCm_BlockType.IOD_BLOCK_REQ_PLUGIN_ALARM_APPLICATION_READY;
+  }
+
+  public PnIoCm_Block_ReqPluginAlarmApplicationReady() {
+    super();
+  }
+
+  @Override
+  protected void serializePnIoCm_BlockChild(WriteBuffer writeBuffer) throws SerializationException {
+    PositionAware positionAware = writeBuffer;
+    boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+    writeBuffer.pushContext("PnIoCm_Block_ReqPluginAlarmApplicationReady");
+
+    writeBuffer.popContext("PnIoCm_Block_ReqPluginAlarmApplicationReady");
+  }
+
+  @Override
+  public int getLengthInBytes() {
+    return (int) Math.ceil((float) getLengthInBits() / 8.0);
+  }
+
+  @Override
+  public int getLengthInBits() {
+    int lengthInBits = super.getLengthInBits();
+    PnIoCm_Block_ReqPluginAlarmApplicationReady _value = this;
+    boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+
+    return lengthInBits;
+  }
+
+  public static PnIoCm_BlockBuilder staticParsePnIoCm_BlockBuilder(ReadBuffer readBuffer)
+      throws ParseException {
+    readBuffer.pullContext("PnIoCm_Block_ReqPluginAlarmApplicationReady");
+    PositionAware positionAware = readBuffer;
+    boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+
+    readBuffer.closeContext("PnIoCm_Block_ReqPluginAlarmApplicationReady");
+    // Create the instance
+    return new PnIoCm_Block_ReqPluginAlarmApplicationReadyBuilderImpl();
+  }
+
+  public static class PnIoCm_Block_ReqPluginAlarmApplicationReadyBuilderImpl
+      implements PnIoCm_Block.PnIoCm_BlockBuilder {
+
+    public PnIoCm_Block_ReqPluginAlarmApplicationReadyBuilderImpl() {}
+
+    public PnIoCm_Block_ReqPluginAlarmApplicationReady build() {
+      PnIoCm_Block_ReqPluginAlarmApplicationReady pnIoCm_Block_ReqPluginAlarmApplicationReady =
+          new PnIoCm_Block_ReqPluginAlarmApplicationReady();
+      return pnIoCm_Block_ReqPluginAlarmApplicationReady;
+    }
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof PnIoCm_Block_ReqPluginAlarmApplicationReady)) {
+      return false;
+    }
+    PnIoCm_Block_ReqPluginAlarmApplicationReady that =
+        (PnIoCm_Block_ReqPluginAlarmApplicationReady) 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-ng/src/main/java/org/apache/plc4x/java/profinet/context/ProfinetDriverContext.java b/plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/context/ProfinetDriverContext.java
index 684dd86f72..3893fac0b6 100644
--- a/plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/context/ProfinetDriverContext.java
+++ b/plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/context/ProfinetDriverContext.java
@@ -21,18 +21,16 @@ package org.apache.plc4x.java.profinet.context;
 
 import org.apache.commons.codec.DecoderException;
 import org.apache.commons.codec.binary.Hex;
-import org.apache.plc4x.java.profinet.gsdml.ProfinetISO15745Profile;
+import org.apache.plc4x.java.profinet.gsdml.ProfinetDeviceAccessPointItem;
+import org.apache.plc4x.java.profinet.gsdml.ProfinetModuleItem;
+import org.apache.plc4x.java.profinet.gsdml.ProfinetVirtualSubmoduleItem;
 import org.apache.plc4x.java.profinet.readwrite.DceRpc_ActivityUuid;
-import org.apache.plc4x.java.profinet.readwrite.DceRpc_Packet;
-import org.apache.plc4x.java.profinet.readwrite.PnIoCm_Block_RealIdentificationData;
 import org.apache.plc4x.java.profinet.readwrite.Uuid;
-import org.apache.plc4x.java.spi.ConversationContext;
 import org.apache.plc4x.java.spi.context.DriverContext;
 import org.apache.plc4x.java.spi.generation.*;
 
-import java.net.DatagramSocket;
-import java.net.SocketException;
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -47,13 +45,13 @@ public class ProfinetDriverContext implements DriverContext {
     private int deviceId;
 
     private String dapId;
+    private ProfinetDeviceAccessPointItem dap;
+    private Map<Integer, ProfinetModuleItem> moduleIndex;
+    private Map<Integer, Map<Integer, ProfinetVirtualSubmoduleItem>> submoduleIndex;
 
     private int localPort;
     private int remotePortImplicitCommunication;
 
-    private ProfinetISO15745Profile deviceProfile;
-    private PnIoCm_Block_RealIdentificationData identificationData;
-
     // PN-CM Related:
     private final DceRpc_ActivityUuid activityUuid;
     private final Uuid applicationRelationUuid;
@@ -142,20 +140,28 @@ public class ProfinetDriverContext implements DriverContext {
         this.dapId = dapId;
     }
 
-    public ProfinetISO15745Profile getDeviceProfile() {
-        return deviceProfile;
+    public ProfinetDeviceAccessPointItem getDap() {
+        return dap;
+    }
+
+    public void setDap(ProfinetDeviceAccessPointItem dap) {
+        this.dap = dap;
+    }
+
+    public Map<Integer, ProfinetModuleItem> getModuleIndex() {
+        return moduleIndex;
     }
 
-    public void setDeviceProfile(ProfinetISO15745Profile deviceProfile) {
-        this.deviceProfile = deviceProfile;
+    public void setModuleIndex(Map<Integer, ProfinetModuleItem> moduleIndex) {
+        this.moduleIndex = moduleIndex;
     }
 
-    public PnIoCm_Block_RealIdentificationData getIdentificationData() {
-        return identificationData;
+    public Map<Integer, Map<Integer, ProfinetVirtualSubmoduleItem>> getSubmoduleIndex() {
+        return submoduleIndex;
     }
 
-    public void setIdentificationData(PnIoCm_Block_RealIdentificationData identificationData) {
-        this.identificationData = identificationData;
+    public void setSubmoduleIndex(Map<Integer, Map<Integer, ProfinetVirtualSubmoduleItem>> submoduleIndex) {
+        this.submoduleIndex = submoduleIndex;
     }
 
     public DceRpc_ActivityUuid getActivityUuid() {
diff --git a/plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/gsdml/ProfinetDataItem.java b/plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/gsdml/ProfinetDataItem.java
index 2ceee0ce51..33d4ed857d 100644
--- a/plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/gsdml/ProfinetDataItem.java
+++ b/plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/gsdml/ProfinetDataItem.java
@@ -54,6 +54,10 @@ public class ProfinetDataItem {
         return textId;
     }
 
+    public void setTextId(String textId) {
+        this.textId = textId;
+    }
+
     public int getLength() {
         return length;
     }
diff --git a/plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetProtocolLogic.java b/plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetProtocolLogic.java
index d95029f517..b1de93aa68 100644
--- a/plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetProtocolLogic.java
+++ b/plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetProtocolLogic.java
@@ -21,9 +21,8 @@ package org.apache.plc4x.java.profinet.protocol;
 
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-import org.apache.plc4x.java.api.messages.PlcBrowseItem;
-import org.apache.plc4x.java.api.messages.PlcBrowseRequest;
-import org.apache.plc4x.java.api.messages.PlcBrowseResponse;
+import org.apache.plc4x.java.api.messages.*;
+import org.apache.plc4x.java.api.model.PlcSubscriptionTag;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.profinet.config.ProfinetConfiguration;
 import org.apache.plc4x.java.profinet.context.ProfinetDriverContext;
@@ -108,7 +107,6 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> imp
                 context.getChannel().close();
                 return;
             }
-            driverContext.setDeviceProfile(deviceProfile);
 
             // If the user provided a DAP id in the connection string, use that (after checking that it exists)
             if (configuration.dapId != null) {
@@ -121,7 +119,6 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> imp
                 if(driverContext.getDapId() == null) {
                     logger.error("Couldn't find requested device access points (DAP): {}", configuration.dapId);
                     context.getChannel().close();
-                    return;
                 }
             }
 
@@ -136,11 +133,16 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> imp
             // correct port, and we can calculate the object id based on the vendor id and device id, which we
             // already have from the discovery.
 
-            // If there's more than one DAP, read the I&M0 block to get the order number,
-            // which allows us to find out which DAP to use.
-            else if(deviceProfile.getProfileBody().getApplicationProcess().getDeviceAccessPointList().size() > 1) {
-                RawSocketChannel pnChannel = ((RawSocketChannel) context.getChannel());
+            // If there's more at least one DAP, read the real identification data and prepare all the data-structures.
+            else if(deviceProfile.getProfileBody().getApplicationProcess().getDeviceAccessPointList().size() > 0) {
+                // Build an index of the String names.
+                Map<String, String> textMapping = new HashMap<>();
+                for (ProfinetTextIdValue profinetTextIdValue : deviceProfile.getProfileBody().getApplicationProcess().getExternalTextList().getPrimaryLanguage().getText()) {
+                    textMapping.put(profinetTextIdValue.getTextId(), profinetTextIdValue.getValue());
+                }
+
                 // Try to read the RealIdentificationData ...
+                RawSocketChannel pnChannel = ((RawSocketChannel) context.getChannel());
                 CompletableFuture<PnIoCm_Block_RealIdentificationData> future1 =
                     PnDcpPacketFactory.sendRealIdentificationDataRequest(context, pnChannel, driverContext);
                 future1.whenComplete((realIdentificationData, throwable1) -> {
@@ -149,21 +151,26 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> imp
                         context.getChannel().close();
                         return;
                     }
-                    driverContext.setIdentificationData(realIdentificationData);
 
-                    // Get the module identification number of slot 0 (Which is always the DAP)
-                    long dapModuleIdentificationNumber = 0;
-                    outerLoop:
+                    // Build an index of all identification numbers for each slot and subslot the device supports.
+                    Map<Integer, Long> slotModuleIdentificationNumbers = new HashMap<>();
+                    Map<Integer, Map<Integer, Long>> subslotModuleIdentificationNumbers = new HashMap<>();
                     for (PnIoCm_RealIdentificationApi api : realIdentificationData.getApis()) {
-                        for (PnIoCm_RealIdentificationApi_Slot slot : api.getSlots()) {
-                            if(slot.getSlotNumber() == 0) {
-                                dapModuleIdentificationNumber = slot.getModuleIdentNumber();
-                                break outerLoop;
+                        for (PnIoCm_RealIdentificationApi_Slot curSlot : api.getSlots()) {
+                            slotModuleIdentificationNumbers.put(curSlot.getSlotNumber(), curSlot.getModuleIdentNumber());
+                            if(!subslotModuleIdentificationNumbers.containsKey(curSlot.getSlotNumber())) {
+                                subslotModuleIdentificationNumbers.put(curSlot.getSlotNumber(), new HashMap<>());
+                            }
+                            for (PnIoCm_RealIdentificationApi_Subslot curSubslot : curSlot.getSubslots()) {
+                                subslotModuleIdentificationNumbers.get(curSlot.getSlotNumber()).put(curSubslot.getSubslotNumber(), curSubslot.getSubmoduleIdentNumber());
                             }
                         }
                     }
+
+                    // Get the module identification number of slot 0 (Which is always the DAP)
+                    long dapModuleIdentificationNumber = slotModuleIdentificationNumbers.get(0);
                     if(dapModuleIdentificationNumber == 0){
-                        logger.error("Unable to detect device access point, closing channel...", throwable1);
+                        logger.error("Unable to detect device access point, closing channel...");
                         context.getChannel().close();
                         return;
                     }
@@ -176,17 +183,78 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> imp
                         }
                         long moduleIdentNumber = Long.parseLong(moduleIdentNumberStr, 16);
                         if(moduleIdentNumber == dapModuleIdentificationNumber) {
-                            driverContext.setDapId(curDap.getId());
+                            driverContext.setDap(curDap);
                             break;
                         }
                     }
                     // Abort, if we weren't able to detect a DAP.
-                    if(driverContext.getDapId() == null) {
+                    if(driverContext.getDap() == null) {
                         logger.error("Unable to auto-detect the device access point, closing channel...");
                         context.getChannel().close();
                         return;
                     }
 
+                    // Iterate through all available modules and find the ones we're using and build an index of them.
+                    Map<Integer, ProfinetModuleItem> moduleIndex = new HashMap<>();
+                    Map<Integer, Map<Integer, ProfinetVirtualSubmoduleItem>> submoduleIndex = new HashMap<>();
+                    for (Map.Entry<Integer, Long> moduleEntry : slotModuleIdentificationNumbers.entrySet()) {
+                        int curSlot = moduleEntry.getKey();
+                        // Slot 0 is the DAP, so we'll continue with the next one.
+                        if(curSlot == 0) {
+                            continue;
+                        }
+                        long curModuleIdentifier = moduleEntry.getValue();
+                        // Find the module that has the given module ident number.
+                        for (ProfinetModuleItem curModule : deviceProfile.getProfileBody().getApplicationProcess().getModuleList()) {
+                            String moduleIdentNumberStr = curModule.getModuleIdentNumber();
+                            if(moduleIdentNumberStr.startsWith("0x") || moduleIdentNumberStr.startsWith("0X")) {
+                                moduleIdentNumberStr = moduleIdentNumberStr.substring(2);
+                            }
+                            long moduleIdentNumber = Long.parseLong(moduleIdentNumberStr, 16);
+                            if(curModuleIdentifier == moduleIdentNumber) {
+                                moduleIndex.put(curSlot, curModule);
+
+                                // Now get all submodules of this module.
+                                Map<Integer, Long> curSubmoduleIndex = subslotModuleIdentificationNumbers.get(curSlot);
+                                for (Map.Entry<Integer, Long> submoduleEntry : curSubmoduleIndex.entrySet()) {
+                                    int curSubslot = submoduleEntry.getKey();
+                                    long curSubmoduleIdentNumber = submoduleEntry.getValue();
+                                    for (ProfinetVirtualSubmoduleItem curSubmodule : curModule.getVirtualSubmoduleList()) {
+                                        String submoduleIdentNumberStr = curSubmodule.getSubmoduleIdentNumber();
+                                        if(submoduleIdentNumberStr.startsWith("0x") || submoduleIdentNumberStr.startsWith("0X")) {
+                                            submoduleIdentNumberStr = submoduleIdentNumberStr.substring(2);
+                                        }
+                                        long submoduleIdentNumber = Long.parseLong(submoduleIdentNumberStr, 16);
+                                        if(curSubmoduleIdentNumber == submoduleIdentNumber) {
+                                            if(!submoduleIndex.containsKey(curSlot)) {
+                                                submoduleIndex.put(curSlot, new HashMap<>());
+                                            }
+                                            submoduleIndex.get(curSlot).put(curSubslot, curSubmodule);
+
+                                            // Replace the text-ids with readable values
+                                            for (ProfinetIoDataInput profinetIoDataInput : curSubmodule.getIoData().getInput()) {
+                                                for (ProfinetDataItem profinetDataItem : profinetIoDataInput.getDataItemList()) {
+                                                    if(textMapping.containsKey(profinetDataItem.getTextId())) {
+                                                        profinetDataItem.setTextId(textMapping.get(profinetDataItem.getTextId()));
+                                                    }
+                                                }
+                                            }
+                                            for (ProfinetIoDataOutput profinetIoDataOutput : curSubmodule.getIoData().getOutput()) {
+                                                for (ProfinetDataItem profinetDataItem : profinetIoDataOutput.getDataItemList()) {
+                                                    if(textMapping.containsKey(profinetDataItem.getTextId())) {
+                                                        profinetDataItem.setTextId(textMapping.get(profinetDataItem.getTextId()));
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    driverContext.setModuleIndex(moduleIndex);
+                    driverContext.setSubmoduleIndex(submoduleIndex);
+
                     context.fireConnected();
                 });
                 // Try to read the I&M0 block
@@ -227,12 +295,6 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> imp
                 });*/
             }
 
-            // If the current device only has one DAP (like most devices), simply use that.
-            else if (deviceProfile.getProfileBody().getApplicationProcess().getDeviceAccessPointList().size() == 1) {
-                driverContext.setDapId(deviceProfile.getProfileBody().getApplicationProcess().getDeviceAccessPointList().get(0).getId());
-                context.fireConnected();
-            }
-
             else {
                 logger.error("GSD descriptor doesn't contain any device access points");
                 context.getChannel().close();
@@ -247,102 +309,45 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> imp
 
     @Override
     public CompletableFuture<PlcBrowseResponse> browse(PlcBrowseRequest browseRequest) {
-        if (driverContext.getDeviceProfile() == null) {
-            return CompletableFuture.failedFuture(new PlcConnectionException("Unable to find GSD file for given device"));
-        }
-        if (driverContext.getDapId() == null) {
-            return CompletableFuture.failedFuture(new PlcConnectionException("DAP not set"));
-        }
-
-        ProfinetISO15745Profile deviceProfile = driverContext.getDeviceProfile();
-
-        // Build an index of all modules.
-        Map<Long, ProfinetModuleItem> moduleMap = new HashMap<>();
-        for (ProfinetModuleItem profinetModuleItem : deviceProfile.getProfileBody().getApplicationProcess().getModuleList()) {
-            String moduleIdentNumberString = profinetModuleItem.getModuleIdentNumber();
-            if(moduleIdentNumberString.startsWith("0x") || moduleIdentNumberString.startsWith("0X")) {
-                moduleIdentNumberString = moduleIdentNumberString.substring(2);
-            }
-            long moduleIdentNumber = Long.parseLong(moduleIdentNumberString,16);
-            moduleMap.put(moduleIdentNumber, profinetModuleItem);
-        }
-
-        // Build an index of the String names.
-        Map<String, String> textMapping = new HashMap<>();
-        for (ProfinetTextIdValue profinetTextIdValue : deviceProfile.getProfileBody().getApplicationProcess().getExternalTextList().getPrimaryLanguage().getText()) {
-            textMapping.put(profinetTextIdValue.getTextId(), profinetTextIdValue.getValue());
-        }
-
         Map<String, PlcResponseCode> responseCodes = new HashMap<>();
         Map<String, List<PlcBrowseItem>> values = new HashMap<>();
         for (String queryName : browseRequest.getQueryNames()) {
             List<PlcBrowseItem> items = new ArrayList<>();
-            for (PnIoCm_RealIdentificationApi api : driverContext.getIdentificationData().getApis()) {
-                for (PnIoCm_RealIdentificationApi_Slot slot : api.getSlots()) {
-                    // Slot 0 is always the DAP module, I haven't come across any DataItems here ...
-                    if(slot.getSlotNumber() == 0) {
-                        continue;
-                    }
-
-                    // Find the matching module.
-                    long moduleIdentNumber = slot.getModuleIdentNumber();
-                    ProfinetModuleItem slotModule = moduleMap.get(moduleIdentNumber);
-                    if(slotModule == null) {
-                        return CompletableFuture.failedFuture(new PlcRuntimeException(
-                            "Module with ident number " + moduleIdentNumber + " not found in GSD."));
-                    }
-
-                    for (PnIoCm_RealIdentificationApi_Subslot subslot : slot.getSubslots()) {
-                        // Find the submodule
-                        ProfinetVirtualSubmoduleItem subSlotSubModule = null;
-                        String moduleIdentNumberHex = String.format("0x%08X", subslot.getSubmoduleIdentNumber());
-                        for (ProfinetVirtualSubmoduleItem virtualSubmoduleItem : slotModule.getVirtualSubmoduleList()) {
-                            if (virtualSubmoduleItem.getSubmoduleIdentNumber().equalsIgnoreCase(moduleIdentNumberHex)) {
-                                subSlotSubModule = virtualSubmoduleItem;
-                                break;
-                            }
-                        }
-                        if (subSlotSubModule == null) {
-                            return CompletableFuture.failedFuture(new PlcRuntimeException(
-                                "SubModule with ident number " + subslot.getSubmoduleIdentNumber() + " not found in GSD."));
-                       }
-
-                        // Add all the input tags.
-                        for (ProfinetIoDataInput profinetIoDataInput : subSlotSubModule.getIoData().getInput()) {
-                            for (int i = 0; i < profinetIoDataInput.getDataItemList().size(); i++) {
-                                ProfinetDataItem profinetDataItem = profinetIoDataInput.getDataItemList().get(i);
-                                ProfinetDataTypeMapper.DataTypeInformation dataTypeInformation =
-                                    ProfinetDataTypeMapper.getPlcValueType(profinetDataItem);
-                                String name = profinetDataItem.getTextId();
-                                // Try to replace the text id with a meaningful value.
-                                if (textMapping.containsKey(name)) {
-                                    name = textMapping.get(name);
-                                }
-                                items.add(new DefaultPlcBrowseItem(new ProfinetTag(
-                                    slot.getSlotNumber(), subslot.getSubslotNumber(), ProfinetTag.Direction.INPUT,
-                                    i, dataTypeInformation.getPlcValueType(), dataTypeInformation.getNumElements()),
-                                    name, false, true, true,
-                                    Collections.emptyMap(), Collections.emptyMap()));
-                            }
+            for(Map.Entry<Integer, Map<Integer, ProfinetVirtualSubmoduleItem>> slotEntry : driverContext.getSubmoduleIndex().entrySet()) {
+                int slot = slotEntry.getKey();
+                for(Map.Entry<Integer, ProfinetVirtualSubmoduleItem> subslotEntry: slotEntry.getValue().entrySet()) {
+                    int subslot = subslotEntry.getKey();
+                    ProfinetVirtualSubmoduleItem subslotModule = subslotEntry.getValue();
+
+                    // Add all the input tags.
+                    for (ProfinetIoDataInput profinetIoDataInput : subslotModule.getIoData().getInput()) {
+                        for (int i = 0; i < profinetIoDataInput.getDataItemList().size(); i++) {
+                            ProfinetDataItem profinetDataItem = profinetIoDataInput.getDataItemList().get(i);
+                            ProfinetDataTypeMapper.DataTypeInformation dataTypeInformation =
+                                ProfinetDataTypeMapper.getPlcValueType(profinetDataItem);
+                            // The ids have been replaced by real textual values in the connection phase.
+                            String name = profinetDataItem.getTextId();
+                            items.add(new DefaultPlcBrowseItem(new ProfinetTag(
+                                slot, subslot, ProfinetTag.Direction.INPUT,
+                                i, dataTypeInformation.getPlcValueType(), dataTypeInformation.getNumElements()),
+                                name, false, true, true,
+                                Collections.emptyMap(), Collections.emptyMap()));
                         }
+                    }
 
-                        // Add all the output tags.
-                        for (ProfinetIoDataOutput profinetIoDataOutput : subSlotSubModule.getIoData().getOutput()) {
-                            for (int i = 0; i < profinetIoDataOutput.getDataItemList().size(); i++) {
-                                ProfinetDataItem profinetDataItem = profinetIoDataOutput.getDataItemList().get(i);
-                                ProfinetDataTypeMapper.DataTypeInformation dataTypeInformation =
-                                    ProfinetDataTypeMapper.getPlcValueType(profinetDataItem);
-                                String name = profinetDataItem.getTextId();
-                                // Try to replace the text id with a meaningful value.
-                                if (textMapping.containsKey(name)) {
-                                    name = textMapping.get(name);
-                                }
-                                items.add(new DefaultPlcBrowseItem(new ProfinetTag(
-                                    slot.getSlotNumber(), subslot.getSubslotNumber(), ProfinetTag.Direction.OUTPUT,
-                                    i, dataTypeInformation.getPlcValueType(), dataTypeInformation.getNumElements()),
-                                    name, false, true, true,
-                                    Collections.emptyMap(), Collections.emptyMap()));
-                            }
+                    // Add all the output tags.
+                    for (ProfinetIoDataOutput profinetIoDataOutput : subslotModule.getIoData().getOutput()) {
+                        for (int i = 0; i < profinetIoDataOutput.getDataItemList().size(); i++) {
+                            ProfinetDataItem profinetDataItem = profinetIoDataOutput.getDataItemList().get(i);
+                            ProfinetDataTypeMapper.DataTypeInformation dataTypeInformation =
+                                ProfinetDataTypeMapper.getPlcValueType(profinetDataItem);
+                            // The ids have been replaced by real textual values in the connection phase.
+                            String name = profinetDataItem.getTextId();
+                            items.add(new DefaultPlcBrowseItem(new ProfinetTag(
+                                slot, subslot, ProfinetTag.Direction.OUTPUT,
+                                i, dataTypeInformation.getPlcValueType(), dataTypeInformation.getNumElements()),
+                                name, false, true, true,
+                                Collections.emptyMap(), Collections.emptyMap()));
                         }
                     }
                 }
@@ -354,6 +359,28 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> imp
         return CompletableFuture.completedFuture(response);
     }
 
+    @Override
+    public CompletableFuture<PlcSubscriptionResponse> subscribe(PlcSubscriptionRequest subscriptionRequest) {
+        // When subscribing, we actually set up the PN IO Application Relation and make the remote device start sending data.
+        if (driverContext.getDap() == null) {
+            return CompletableFuture.failedFuture(new PlcConnectionException("DAP not set"));
+        }
+
+        // Find the matching data in the device descriptor.
+        for (String tagName : subscriptionRequest.getTagNames()) {
+            PlcSubscriptionTag tag = subscriptionRequest.getTag(tagName);
+            if(!(tag instanceof ProfinetTag)) {
+                // TODO: Add an error code for this field.
+                continue;
+            }
+            ProfinetTag profinetTag = (ProfinetTag) tag;
+            int slot = profinetTag.getSlot();
+            int subSlot = profinetTag.getSubSlot();
+
+        }
+        return null;
+    }
+
     protected void extractBlockInfo(List<PnDcp_Block> blocks) {
         // Index the blocks of the response
         Map<String, PnDcp_Block> blockMap = new HashMap<>();
diff --git a/plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/utils/ProfinetDataTypeMapper.java b/plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/utils/ProfinetDataTypeMapper.java
index bb420b3760..70e8f96585 100644
--- a/plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/utils/ProfinetDataTypeMapper.java
+++ b/plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/utils/ProfinetDataTypeMapper.java
@@ -70,7 +70,11 @@ public class ProfinetDataTypeMapper {
                 case "VisibleString":
                     break;
                 case "OctetString":
-                    return new DataTypeInformation(PlcValueType.BOOL, dataItem.getLength());
+                    if(dataItem.isUseAsBits()) {
+                        return new DataTypeInformation(PlcValueType.List, dataItem.getLength() * 8);
+                    } else {
+                        return new DataTypeInformation(PlcValueType.List, dataItem.getLength());
+                    }
                 case "Unsigned8+Unsigned8":
                 case "Float32+Unsigned8":
                 case "Float32+Status8":
diff --git a/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Block.java b/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Block.java
index e4bf5c8538..4065b85537 100644
--- a/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Block.java
+++ b/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Block.java
@@ -149,6 +149,10 @@ public abstract class PnIoCm_Block implements Message {
       builder = PnIoCm_Block_ArServer.staticParsePnIoCm_BlockBuilder(readBuffer);
     } else if (EvaluationHelper.equals(blockType, PnIoCm_BlockType.REAL_IDENTIFICATION_DATA)) {
       builder = PnIoCm_Block_RealIdentificationData.staticParsePnIoCm_BlockBuilder(readBuffer);
+    } else if (EvaluationHelper.equals(
+        blockType, PnIoCm_BlockType.IOD_BLOCK_REQ_PLUGIN_ALARM_APPLICATION_READY)) {
+      builder =
+          PnIoCm_Block_ReqPluginAlarmApplicationReady.staticParsePnIoCm_BlockBuilder(readBuffer);
     } else if (EvaluationHelper.equals(blockType, PnIoCm_BlockType.I_AND_M_0)) {
       builder = PnIoCm_Block_IAndM0.staticParsePnIoCm_BlockBuilder(readBuffer);
     } else if (EvaluationHelper.equals(blockType, PnIoCm_BlockType.I_AND_M_1)) {
diff --git a/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Block_ReqPluginAlarmApplicationReady.java b/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Block_ReqPluginAlarmApplicationReady.java
new file mode 100644
index 0000000000..73b9d230c4
--- /dev/null
+++ b/plc4j/drivers/profinet/src/main/generated/org/apache/plc4x/java/profinet/readwrite/PnIoCm_Block_ReqPluginAlarmApplicationReady.java
@@ -0,0 +1,123 @@
+/*
+ * 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_Block_ReqPluginAlarmApplicationReady extends PnIoCm_Block implements Message {
+
+  // Accessors for discriminator values.
+  public PnIoCm_BlockType getBlockType() {
+    return PnIoCm_BlockType.IOD_BLOCK_REQ_PLUGIN_ALARM_APPLICATION_READY;
+  }
+
+  public PnIoCm_Block_ReqPluginAlarmApplicationReady() {
+    super();
+  }
+
+  @Override
+  protected void serializePnIoCm_BlockChild(WriteBuffer writeBuffer) throws SerializationException {
+    PositionAware positionAware = writeBuffer;
+    boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+    writeBuffer.pushContext("PnIoCm_Block_ReqPluginAlarmApplicationReady");
+
+    writeBuffer.popContext("PnIoCm_Block_ReqPluginAlarmApplicationReady");
+  }
+
+  @Override
+  public int getLengthInBytes() {
+    return (int) Math.ceil((float) getLengthInBits() / 8.0);
+  }
+
+  @Override
+  public int getLengthInBits() {
+    int lengthInBits = super.getLengthInBits();
+    PnIoCm_Block_ReqPluginAlarmApplicationReady _value = this;
+    boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+
+    return lengthInBits;
+  }
+
+  public static PnIoCm_BlockBuilder staticParsePnIoCm_BlockBuilder(ReadBuffer readBuffer)
+      throws ParseException {
+    readBuffer.pullContext("PnIoCm_Block_ReqPluginAlarmApplicationReady");
+    PositionAware positionAware = readBuffer;
+    boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+
+    readBuffer.closeContext("PnIoCm_Block_ReqPluginAlarmApplicationReady");
+    // Create the instance
+    return new PnIoCm_Block_ReqPluginAlarmApplicationReadyBuilderImpl();
+  }
+
+  public static class PnIoCm_Block_ReqPluginAlarmApplicationReadyBuilderImpl
+      implements PnIoCm_Block.PnIoCm_BlockBuilder {
+
+    public PnIoCm_Block_ReqPluginAlarmApplicationReadyBuilderImpl() {}
+
+    public PnIoCm_Block_ReqPluginAlarmApplicationReady build() {
+      PnIoCm_Block_ReqPluginAlarmApplicationReady pnIoCm_Block_ReqPluginAlarmApplicationReady =
+          new PnIoCm_Block_ReqPluginAlarmApplicationReady();
+      return pnIoCm_Block_ReqPluginAlarmApplicationReady;
+    }
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof PnIoCm_Block_ReqPluginAlarmApplicationReady)) {
+      return false;
+    }
+    PnIoCm_Block_ReqPluginAlarmApplicationReady that =
+        (PnIoCm_Block_ReqPluginAlarmApplicationReady) 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/protocols/profinet/src/main/resources/protocols/profinet/pnio.mspec b/protocols/profinet/src/main/resources/protocols/profinet/pnio.mspec
index 079d456ea2..4518b0eec5 100644
--- a/protocols/profinet/src/main/resources/protocols/profinet/pnio.mspec
+++ b/protocols/profinet/src/main/resources/protocols/profinet/pnio.mspec
@@ -335,6 +335,9 @@
             [implicit uint 16                      numApis          'COUNT(apis)'                ]
             [array    PnIoCm_RealIdentificationApi apis             count               'numApis']
         ]
+        ['IOD_BLOCK_REQ_PLUGIN_ALARM_APPLICATION_READY' PnIoCm_Block_ReqPluginAlarmApplicationReady
+            // TODO: Implement ...
+        ]
 
         // https://cache.industry.siemens.com/dl/files/491/26435491/att_859456/v1/PGH_IO-Base_0.pdf (page 231)
         ['I_AND_M_0' PnIoCm_Block_IAndM0


[plc4x] 01/02: chore(plc4j/profinet): - Added some more comments

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 ee0db37493e11479667b1acab5310084bbe556ae
Author: Christofer Dutz <cd...@apache.org>
AuthorDate: Sun Jun 11 12:03:22 2023 +0200

    chore(plc4j/profinet):
     - Added some more comments
---
 .../plc4x/java/profinet/device/ProfinetDevice.java     | 18 +++++++++---------
 .../plc4x/java/profinet/device/ProfinetModuleImpl.java |  2 ++
 .../plc4x/java/profinet/ManualProfinetIoTest.java      |  3 ---
 3 files changed, 11 insertions(+), 12 deletions(-)

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 be95940400..2003b99509 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
@@ -203,9 +203,9 @@ public class ProfinetDevice implements PlcSubscriber {
                             // string and also tell the device about the data we'll be publishing.
                             case IDLE:
                                 CreateConnection createConnection = new CreateConnection();
-                                // Send the packet ...
+                                // Send the packet and process the response ...
                                 recordIdAndSend(createConnection);
-                                // Wait for the response ...
+                                // Wait for it to be finished processing ...
                                 createConnection.getResponseHandled().get(timeout, TimeUnit.NANOSECONDS);
                                 break;
                             // TODO: It seems this state is never used?
@@ -520,13 +520,6 @@ public class ProfinetDevice implements PlcSubscriber {
                     deviceContext.getInputIoCsApiBlocks())
             );
 
-            List<PnIoCm_IoCrBlockReqApi> outputApis = Collections.singletonList(
-                new PnIoCm_IoCrBlockReqApi(
-                    deviceContext.getOutputIoPsApiBlocks(),
-                    deviceContext.getOutputIoCsApiBlocks()
-                )
-            );
-
             deviceContext.setInputReq(new PnIoCm_Block_IoCrReq(
                 (short) 1,
                 (short) 0,
@@ -555,6 +548,13 @@ public class ProfinetDevice implements PlcSubscriber {
 
             blocks.add(deviceContext.getInputReq());
 
+            List<PnIoCm_IoCrBlockReqApi> outputApis = Collections.singletonList(
+                new PnIoCm_IoCrBlockReqApi(
+                    deviceContext.getOutputIoPsApiBlocks(),
+                    deviceContext.getOutputIoCsApiBlocks()
+                )
+            );
+
             deviceContext.setOutputReq(new PnIoCm_Block_IoCrReq(
                 (short) 1,
                 (short) 0,
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/device/ProfinetModuleImpl.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/device/ProfinetModuleImpl.java
index 751b42162a..e2c4d97786 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/device/ProfinetModuleImpl.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/device/ProfinetModuleImpl.java
@@ -60,7 +60,9 @@ public class ProfinetModuleImpl implements ProfinetModule {
     }
 
     private void populateNode() {
+        // IOPS = IO Producer Status
         int inputIoPsOffset = ioPsOffset;
+        // IOCS = IO Consumer Status
         int outputIoCsOffset = ioCsOffset;
 
         for (ProfinetVirtualSubmoduleItem virtualItem : module.getVirtualSubmoduleList()) {
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 bb5b854553..0836021331 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
@@ -47,14 +47,11 @@ public class ManualProfinetIoTest {
                 System.out.println(value.getTag().getAddressString());
             }
         }
-        System.out.println(plcBrowseResponse);
         // 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();
         PlcSubscriptionRequest.Builder builder = connection.subscriptionRequestBuilder();
         builder.addChangeOfStateTag("Input 4", ProfinetTag.of("cdxb195b3.1.1.Inputs.2:BOOL"));
         PlcSubscriptionRequest request = builder.build();