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

[plc4x] 02/02: fix(plc4j/profinet): Implmented pop for the dcerpc response queue. Syncronized cyclic counter for pnio packets

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

hutcheb pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 40e6a66cd868e78d4890095dc2a0dd4874c3f18d
Author: Ben Hutcheson <be...@gmail.com>
AuthorDate: Sat Feb 11 12:48:51 2023 +0100

    fix(plc4j/profinet): Implmented pop for the dcerpc response queue. Syncronized cyclic counter for pnio packets
---
 .../profinet/context/ProfinetDeviceContext.java    | 14 +++--
 .../java/profinet/device/ProfinetChannel.java      |  3 +-
 .../plc4x/java/profinet/device/ProfinetDevice.java | 73 +++++++++++++++++++---
 .../main/resources/protocols/profinet/pndcp.mspec  | 22 +++----
 4 files changed, 87 insertions(+), 25 deletions(-)

diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/context/ProfinetDeviceContext.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/context/ProfinetDeviceContext.java
index e0152ce053..128f89fa98 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/context/ProfinetDeviceContext.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/context/ProfinetDeviceContext.java
@@ -459,12 +459,18 @@ public class ProfinetDeviceContext implements DriverContext, HasConfiguration<Pr
         this.frameId = frameId;
     }
 
-    public Map<Long, ProfinetCallable<DceRpc_Packet>> getQueue() {
-        return queue;
+    public ProfinetCallable<DceRpc_Packet> popFromQueue(long sequenceNumber) {
+        ProfinetCallable<DceRpc_Packet> r = queue.get(sequenceNumber);
+        queue.remove(sequenceNumber);
+        return r;
     }
 
-    public void setQueue(Map<Long, ProfinetCallable<DceRpc_Packet>> queue) {
-        this.queue = queue;
+    public boolean hasSequenecNumberInQueue(long sequenceNumber) {
+        return queue.containsKey(sequenceNumber);
+    }
+
+    public void addToQueue(long sequenceNumber, ProfinetCallable<DceRpc_Packet> obj) {
+        queue.put(sequenceNumber, obj);
     }
 
     public int getSessionKey() {
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 deb608c1e0..d1c1c4ffe8 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
@@ -103,7 +103,7 @@ public class ProfinetChannel {
                     } else if (ethernetPacket.getHeader().getType() == EtherType.IPV4 && ethernetPacket.getPayload().getPayload() instanceof UdpPacket) {
                         UdpPacket payload = (UdpPacket) ethernetPacket.getPayload().getPayload();
                         // Check if it's a PROFINET packet
-                        if (payload.getHeader().getDstPort().value() == -30572 || payload.getHeader().getDstPort().value() == -15536) {
+                        if (payload.getHeader().getDstPort().value() == -30572 || payload.getHeader().getDstPort().value() == -15536 || payload.getHeader().getDstPort().value() == -15535) {
                             isPnPacket = true;
                         }
                     }
@@ -139,7 +139,6 @@ public class ProfinetChannel {
                                         }
                                     }
                                 }
-
                             } else if (payload instanceof Ethernet_FramePayload_LLDP) {
                                 Lldp_Pdu pdu = ((Ethernet_FramePayload_LLDP) payload).getPdu();
                                 if (discoverer != null) {
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 e10de6e0b4..3e281301f5 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
@@ -70,6 +70,8 @@ public class ProfinetDevice implements PlcSubscriber{
     private String deviceId;
     private Thread eventLoop = null;
     Map<String, List<Consumer<PlcSubscriptionEvent>>> registrations = new HashMap<>();
+    private int offset = 0;
+    private boolean firstMessage = true;
 
     public ProfinetDevice(String deviceName, String deviceAccess, String subModules, BiFunction<String, String, ProfinetISO15745Profile> gsdHandler)  {
         this.gsdHandler = gsdHandler;
@@ -123,7 +125,7 @@ public class ProfinetDevice implements PlcSubscriber{
     }
 
     private void recordIdAndSend(ProfinetCallable<DceRpc_Packet> callable) {
-        deviceContext.getQueue().put(callable.getId(), callable);
+        deviceContext.addToQueue(callable.getId(), callable);
         ProfinetMessageWrapper.sendUdpMessage(
             callable,
             deviceContext
@@ -270,8 +272,8 @@ public class ProfinetDevice implements PlcSubscriber{
     public void handleResponse(Ethernet_FramePayload_IPv4 packet) {
         logger.debug("Received packet for {}", packet.getPayload().getObjectUuid());
         long objectId = packet.getPayload().getSequenceNumber();
-        if (deviceContext.getQueue().containsKey(objectId)) {
-            deviceContext.getQueue().get(objectId).handle(packet.getPayload());
+        if (deviceContext.hasSequenecNumberInQueue(objectId)) {
+            deviceContext.popFromQueue(objectId).handle(packet.getPayload());
         } else {
             PnIoCm_Packet payloadPacket = packet.getPayload().getPayload();
             deviceContext.setActivityUuid(packet.getPayload().getActivityUuid());
@@ -283,6 +285,12 @@ public class ProfinetDevice implements PlcSubscriber{
                         deviceContext.setState(ProfinetDeviceState.APPLRDY);
                     }
                 }
+            } else if (payloadPacket instanceof PnIoCm_Packet_Fault) {
+                DceRpcAck ack = new DceRpcAck(deviceContext.getActivityUuid(), deviceContext.getSequenceNumber());
+                recordIdAndSend(ack);
+            } else if (payloadPacket instanceof PnIoCm_Packet_Ping) {
+                DceRpcAck ack = new DceRpcAck(deviceContext.getActivityUuid(), deviceContext.getSequenceNumber());
+                recordIdAndSend(ack);
             } else {
                 deviceContext.setState(ProfinetDeviceState.ABORT);
                 logger.error("Unable to match Response with Requested Profinet packet");
@@ -348,10 +356,12 @@ public class ProfinetDevice implements PlcSubscriber{
         Map<String, ResponseItem<PlcValue>> tags = new HashMap<>();
         ReadBuffer buffer = new ReadBufferByteBased(cyclicPdu.getDataUnit().getData());
 
+        if (firstMessage) {
+            offset = cyclicPdu.getCycleCounter();
+            firstMessage = false;
+        }
+
         try {
-            if (deviceContext.getModules() == null) {
-                logger.error("HH");
-            }
             for (ProfinetModule module : deviceContext.getModules()) {
                 module.parseTags(tags, deviceContext.getDeviceName(), buffer);
             }
@@ -865,6 +875,53 @@ public class ProfinetDevice implements PlcSubscriber{
         }
     }
 
+    public class DceRpcAck implements ProfinetCallable<DceRpc_Packet> {
+
+        private final DceRpc_ActivityUuid activityUuid;
+        private long id;
+
+        public DceRpcAck(DceRpc_ActivityUuid activityUuid, long seqNumber) {
+            this.activityUuid = activityUuid;
+            this.id = seqNumber;
+        }
+
+        public CompletableFuture<Boolean> getResponseHandled() {
+            return null;
+        }
+
+        public long getId() {
+            return id;
+        }
+
+        public void setId(long id) {
+            this.id = id;
+        }
+
+        public DceRpc_Packet create() {
+            return new DceRpc_Packet(
+                DceRpc_PacketType.NO_CALL,
+                false,
+                true,
+                true,
+                IntegerEncoding.BIG_ENDIAN,
+                CharacterEncoding.ASCII,
+                FloatingPointEncoding.IEEE,
+                new DceRpc_ObjectUuid((byte) 0x00, 0x0001, Integer.decode("0x" + deviceId), Integer.decode("0x" + vendorId)),
+                new DceRpc_InterfaceUuid_ControllerInterface(),
+                activityUuid,
+                0,
+                id,
+                DceRpc_Operation.CONTROL,
+                new PnIoCm_Packet_NoCall()
+            );
+        }
+
+        @Override
+        public void handle(DceRpc_Packet packet) {
+            logger.debug("Received an unintented packet");
+        }
+    }
+
     public class CyclicData implements ProfinetCallable<Ethernet_Frame> {
 
         private final long startTime;
@@ -906,7 +963,7 @@ public class ProfinetDevice implements PlcSubscriber{
                     buffer.writeByte((byte) 0x00);
                 }
 
-                int elapsedTime = (int) ((((System.nanoTime() - startTime)/(MIN_CYCLE_NANO_SEC))) % 65536);
+                int elapsedTime = (int) ((((System.nanoTime() - startTime)/(MIN_CYCLE_NANO_SEC)) + offset) % 65536);
 
                 Ethernet_Frame frame = new Ethernet_Frame(
                     deviceContext.getMacAddress(),
@@ -932,7 +989,7 @@ public class ProfinetDevice implements PlcSubscriber{
                 deviceContext.setState(ProfinetDeviceState.ABORT);
                 logger.error("Error serializing cyclic data for device {}", deviceContext.getDeviceName());
 
-                int elapsedTime = (int) ((((System.nanoTime() - startTime)/(MIN_CYCLE_NANO_SEC))) % 65536);
+                int elapsedTime = (int) ((((System.nanoTime() - startTime)/(MIN_CYCLE_NANO_SEC)) + offset) % 65536);
 
                 Ethernet_Frame frame = new Ethernet_Frame(
                     deviceContext.getMacAddress(),
diff --git a/protocols/profinet/src/main/resources/protocols/profinet/pndcp.mspec b/protocols/profinet/src/main/resources/protocols/profinet/pndcp.mspec
index 42a1deb7e6..dbc515c62c 100644
--- a/protocols/profinet/src/main/resources/protocols/profinet/pndcp.mspec
+++ b/protocols/profinet/src/main/resources/protocols/profinet/pndcp.mspec
@@ -70,17 +70,17 @@
             // Delay Parameter End
         ]
         ['Alarm_Low' PnDcp_Pdu_AlarmLow
-                    [simple uint 16 alarmDstEndpoint]
-                    [simple uint 16 alarmSrcEndpoint]
-                    [simple uint 4  version]
-                    [simple uint 4  errorType]
-                    [simple uint 4  tAck]
-                    [simple uint 4  windowSize]
-                    [simple uint 16 senSeqNum]
-                    [simple uint 16 ackSeqNum]
-                    [implicit uint 16 varPartLen 'COUNT(varPart)']
-                    [array    byte varPart                        length              'varPartLen']
-                ]
+            [simple uint 16 alarmDstEndpoint]
+            [simple uint 16 alarmSrcEndpoint]
+            [simple uint 4  version]
+            [simple uint 4  errorType]
+            [simple uint 4  tAck]
+            [simple uint 4  windowSize]
+            [simple uint 16 senSeqNum]
+            [simple uint 16 ackSeqNum]
+            [implicit uint 16 varPartLen 'COUNT(varPart)']
+            [array    byte varPart                        length              'varPartLen']
+        ]
         ['DCP_Identify_ReqPDU' PnDcp_Pdu_IdentifyReq
             [const    uint 8      serviceId                    0x05                                ]
             // ServiceType Start