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

ldywicki pushed a commit to branch feature/profinet2
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 7d0fe2b6f60ff8bc8c6b8e64e1ae552bb2a07c3f
Author: Ɓukasz Dywicki <[email protected]>
AuthorDate: Mon Mar 29 13:55:52 2021 +0200

    Support for tagged ethernet frames.
    
    Some sketch work around subscriptions for ident answers, without actual 
field definitions and concrete implementations.
---
 .../protocols/profinet/profinet.dcp.mspec          |  33 ++++--
 .../java/profinet/dcp/ProfinetDCPPlcDriver.java    |   8 +-
 .../java/profinet/dcp/field/ProfinetDcpField.java  |  24 ++++
 .../dcp/protocol/ProfinetDCPProtocolLogic.java     | 126 ++++++++++++++++++---
 .../protocol/ProfinetDCPSubscriptionHandle.java    |  54 +++++++++
 5 files changed, 217 insertions(+), 28 deletions(-)

diff --git 
a/protocols/profinet/src/main/resources/protocols/profinet/profinet.dcp.mspec 
b/protocols/profinet/src/main/resources/protocols/profinet/profinet.dcp.mspec
index d202968..fb9bf40 100644
--- 
a/protocols/profinet/src/main/resources/protocols/profinet/profinet.dcp.mspec
+++ 
b/protocols/profinet/src/main/resources/protocols/profinet/profinet.dcp.mspec
@@ -17,11 +17,22 @@
 // under the License.
 //
 
-[type 'EthernetFrame'
-    [simple MacAddress 'destination' ]
-    [simple MacAddress 'source'      ]
-    [simple uint 16    'ethernetType']
-    [simple ProfinetFrame 'payload'  ]
+[discriminatedType 'BaseEthernetFrame'
+    [simple        MacAddress    'destination' ]
+    [simple        MacAddress    'source'      ]
+    [simple        uint 16       'etherType']
+    [typeSwitch 'etherType'
+        ['0x8100' TaggedFrame
+            [simple uint 3       'priority']
+            [simple bit          'droppable']
+            [simple uint 12      'vlan']
+            [simple uint 16      'ethernetType']
+        ]
+        [EthernetFrame
+            [implicit uint 16    'ethernetType' 'etherType']
+        ]
+    ]
+    [simple        ProfinetFrame 'payload'     ]
 ]
 
 [type 'ProfinetFrame'
@@ -40,11 +51,19 @@
             [simple uint 16 'dcpDataLength'                ]
             [array DCPBlock 'blocks' length 'dcpDataLength']
         ]
+        ['FrameType.GET_SET' DcpGetSetPDU
+            [enum DCPServiceID 'serviceId'                 ]
+            [enum DCPServiceType 'serviceType'             ]
+            [simple uint 32 'xid'                          ]
+            [reserved uint 16 '0x00'                       ]
+            [simple uint 16 'dcpDataLength'                ]
+            [array DCPBlock 'blocks' length 'dcpDataLength']
+        ]
         ['FrameType.IDENTIFY_RESPONSE' DcpIdentResponsePDU
             [enum DCPServiceID 'serviceId'                 ]
             [enum DCPServiceType 'serviceType'             ]
             [simple uint 32 'xid'                          ]
-            [simple uint 16 'responseDelay'                ]
+            [reserved uint 16 '0x00'                       ]
             [simple uint 16 'dcpDataLength'                ]
             [array DCPBlock 'blocks' length 'dcpDataLength']
         ]
@@ -167,7 +186,6 @@
     ['0x04' SET                         ]
     ['0x05' IDENTIFY                    ]
     ['0x06' HELLO                       ]
-    ['0xFEFE' IDENTIFY_RESPONSE         ]
 ]
 
 [enum uint 8 'DCPServiceType'
@@ -177,6 +195,7 @@
 
 [enum uint 16 'FrameType'
     ['0xFEFE' IDENTIFY_MULTICAST_REQUEST]
+    ['0xFEFD' GET_SET                   ]
     ['0xFEFF' IDENTIFY_RESPONSE         ]
 ]
 
diff --git 
a/sandbox/test-java-profinet-driver/src/main/java/org/apache/plc4x/java/profinet/dcp/ProfinetDCPPlcDriver.java
 
b/sandbox/test-java-profinet-driver/src/main/java/org/apache/plc4x/java/profinet/dcp/ProfinetDCPPlcDriver.java
index 5baa18e..eba4937 100644
--- 
a/sandbox/test-java-profinet-driver/src/main/java/org/apache/plc4x/java/profinet/dcp/ProfinetDCPPlcDriver.java
+++ 
b/sandbox/test-java-profinet-driver/src/main/java/org/apache/plc4x/java/profinet/dcp/ProfinetDCPPlcDriver.java
@@ -24,7 +24,9 @@ import org.apache.plc4x.java.api.value.PlcValueHandler;
 import org.apache.plc4x.java.profinet.dcp.configuration.ProfinetConfiguration;
 import org.apache.plc4x.java.profinet.dcp.field.ProfinetFieldHandler;
 import org.apache.plc4x.java.profinet.dcp.protocol.ProfinetDCPProtocolLogic;
+import org.apache.plc4x.java.profinet.dcp.readwrite.BaseEthernetFrame;
 import org.apache.plc4x.java.profinet.dcp.readwrite.EthernetFrame;
+import org.apache.plc4x.java.profinet.dcp.readwrite.io.BaseEthernetFrameIO;
 import org.apache.plc4x.java.profinet.dcp.readwrite.io.EthernetFrameIO;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
@@ -37,7 +39,7 @@ import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
 /**
  * Proof of concept implementation of Profinet DCP driver.
  */
-public class ProfinetDCPPlcDriver extends GeneratedDriverBase<EthernetFrame> {
+public class ProfinetDCPPlcDriver extends 
GeneratedDriverBase<BaseEthernetFrame> {
 
     @Override
     public String getProtocolCode() {
@@ -70,8 +72,8 @@ public class ProfinetDCPPlcDriver extends 
GeneratedDriverBase<EthernetFrame> {
     }
 
     @Override
-    protected ProtocolStackConfigurer<EthernetFrame> getStackConfigurer() {
-        return SingleProtocolStackConfigurer.builder(EthernetFrame.class, 
EthernetFrameIO.class)
+    protected ProtocolStackConfigurer<BaseEthernetFrame> getStackConfigurer() {
+        return SingleProtocolStackConfigurer.builder(BaseEthernetFrame.class, 
BaseEthernetFrameIO.class)
             .withProtocol(ProfinetDCPProtocolLogic.class)
             .withPacketSizeEstimator(ProfinetPacketEstimator.class)
             .withCorruptPacketRemover(CorruptEthernetFrameRemover.class)
diff --git 
a/sandbox/test-java-profinet-driver/src/main/java/org/apache/plc4x/java/profinet/dcp/field/ProfinetDcpField.java
 
b/sandbox/test-java-profinet-driver/src/main/java/org/apache/plc4x/java/profinet/dcp/field/ProfinetDcpField.java
new file mode 100644
index 0000000..98d92d5
--- /dev/null
+++ 
b/sandbox/test-java-profinet-driver/src/main/java/org/apache/plc4x/java/profinet/dcp/field/ProfinetDcpField.java
@@ -0,0 +1,24 @@
+/*
+ * 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
+ *
+ *   http://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.dcp.field;
+
+import org.apache.plc4x.java.api.model.PlcField;
+
+public class ProfinetDcpField implements PlcField {
+}
diff --git 
a/sandbox/test-java-profinet-driver/src/main/java/org/apache/plc4x/java/profinet/dcp/protocol/ProfinetDCPProtocolLogic.java
 
b/sandbox/test-java-profinet-driver/src/main/java/org/apache/plc4x/java/profinet/dcp/protocol/ProfinetDCPProtocolLogic.java
index 9348d2c..c8ba4a0 100644
--- 
a/sandbox/test-java-profinet-driver/src/main/java/org/apache/plc4x/java/profinet/dcp/protocol/ProfinetDCPProtocolLogic.java
+++ 
b/sandbox/test-java-profinet-driver/src/main/java/org/apache/plc4x/java/profinet/dcp/protocol/ProfinetDCPProtocolLogic.java
@@ -19,18 +19,28 @@
 package org.apache.plc4x.java.profinet.dcp.protocol;
 
 import java.time.Duration;
+import java.time.Instant;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+
+import ch.qos.logback.classic.util.LogbackMDCAdapter;
+import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent;
+import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest;
+import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse;
+import org.apache.plc4x.java.api.model.PlcConsumerRegistration;
+import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
+import org.apache.plc4x.java.api.types.PlcResponseCode;
+import org.apache.plc4x.java.api.types.PlcSubscriptionType;
+import org.apache.plc4x.java.api.value.PlcValue;
 import org.apache.plc4x.java.profinet.dcp.configuration.ProfinetConfiguration;
-import org.apache.plc4x.java.profinet.dcp.readwrite.AllSelector;
-import org.apache.plc4x.java.profinet.dcp.readwrite.DCPBlock;
-import org.apache.plc4x.java.profinet.dcp.readwrite.DcpIdentRequestPDU;
-import org.apache.plc4x.java.profinet.dcp.readwrite.DcpIdentResponsePDU;
-import org.apache.plc4x.java.profinet.dcp.readwrite.DeviceProperties;
-import org.apache.plc4x.java.profinet.dcp.readwrite.EthernetFrame;
-import org.apache.plc4x.java.profinet.dcp.readwrite.IP;
-import org.apache.plc4x.java.profinet.dcp.readwrite.IPv4Address;
-import org.apache.plc4x.java.profinet.dcp.readwrite.MacAddress;
-import org.apache.plc4x.java.profinet.dcp.readwrite.ProfinetFrame;
+import org.apache.plc4x.java.profinet.dcp.field.ProfinetDcpField;
+import org.apache.plc4x.java.profinet.dcp.readwrite.*;
 import org.apache.plc4x.java.profinet.dcp.readwrite.types.DCPBlockOption;
 import org.apache.plc4x.java.profinet.dcp.readwrite.types.DCPServiceID;
 import org.apache.plc4x.java.profinet.dcp.readwrite.types.DCPServiceType;
@@ -38,20 +48,33 @@ import 
org.apache.plc4x.java.profinet.dcp.readwrite.types.FrameType;
 import org.apache.plc4x.java.spi.ConversationContext;
 import org.apache.plc4x.java.spi.Plc4xProtocolBase;
 import org.apache.plc4x.java.spi.configuration.HasConfiguration;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
+import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionEvent;
+import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionRequest;
+import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionResponse;
+import org.apache.plc4x.java.spi.messages.PlcSubscriber;
+import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
+import org.apache.plc4x.java.spi.model.DefaultPlcConsumerRegistration;
+import org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField;
+import org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionHandle;
+import org.apache.plc4x.java.spi.values.PlcNull;
+import org.apache.plc4x.java.spi.values.PlcValues;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * Driver logic for handling Profinet-DCP packets.
  */
-public class ProfinetDCPProtocolLogic extends Plc4xProtocolBase<EthernetFrame> 
implements
-    HasConfiguration<ProfinetConfiguration> {
+public class ProfinetDCPProtocolLogic extends 
Plc4xProtocolBase<BaseEthernetFrame> implements
+    HasConfiguration<ProfinetConfiguration>, PlcSubscriber {
 
     public static MacAddress PROFINET_BROADCAST = createAddress(0x01, 0x0E, 
0xCF, 0x00, 0x00, 0x00);
     public static int PN_DCP = 0x8892;
 
     public static final Duration REQUEST_TIMEOUT = Duration.ofMillis(10000);
     private final Logger logger = 
LoggerFactory.getLogger(ProfinetDCPProtocolLogic.class);
+    private Map<DefaultPlcConsumerRegistration, 
Consumer<PlcSubscriptionEvent>> consumers = new ConcurrentHashMap<>();
 
     private AtomicInteger invokeId = new AtomicInteger(0);
     private ProfinetConfiguration configuration;
@@ -62,7 +85,7 @@ public class ProfinetDCPProtocolLogic extends 
Plc4xProtocolBase<EthernetFrame> i
     }
 
     @Override
-    public void onConnect(ConversationContext<EthernetFrame> context) {
+    public void onConnect(ConversationContext<BaseEthernetFrame> context) {
         DCPServiceID serviceId = DCPServiceID.IDENTIFY;
         DCPServiceType serviceType = DCPServiceType.REQUEST;
         long xid = invokeId.incrementAndGet();
@@ -80,17 +103,48 @@ public class ProfinetDCPProtocolLogic extends 
Plc4xProtocolBase<EthernetFrame> i
     }
 
     @Override
-    public void onDisconnect(ConversationContext<EthernetFrame> context) {
+    public void onDisconnect(ConversationContext<BaseEthernetFrame> context) {
         context.fireDisconnected();
     }
 
     @Override
-    protected void decode(ConversationContext<EthernetFrame> context, 
EthernetFrame msg) throws Exception {
-        if (msg.getEthernetType() != PN_DCP) {
-            logger.trace("Discarding unwanted frame type {}", 
msg.getEthernetType());
+    protected void decode(ConversationContext<BaseEthernetFrame> context, 
BaseEthernetFrame msg) throws Exception {
+        if (msg instanceof TaggedFrame) {
+            TaggedFrame frame = (TaggedFrame) msg;
+            if (frame.getEthernetType() != PN_DCP) {
+                logger.trace("Discarding unwanted frame type {}", 
frame.getEthernetType());
+            }
+        } else if (msg.getEtherType() != PN_DCP) {
+            logger.trace("Discarding unwanted frame type {}", 
msg.getEtherType());
         }
 
         ProfinetFrame profinetFrame = msg.getPayload();
+
+        for (Map.Entry<DefaultPlcConsumerRegistration, 
Consumer<PlcSubscriptionEvent>> entry : consumers.entrySet()) {
+            DefaultPlcConsumerRegistration registration = entry.getKey();
+            Consumer<PlcSubscriptionEvent> consumer = entry.getValue();
+
+            for (PlcSubscriptionHandle handler : 
registration.getSubscriptionHandles()) {
+                ProfinetDCPSubscriptionHandle handle = 
(ProfinetDCPSubscriptionHandle) handler;
+
+                if (handle.matches(profinetFrame)) {
+                    logger.trace("Dispatching frame {} to {}", profinetFrame, 
handle);
+
+                    ProfinetDcpField field = handle.getField();
+                    // todo map actual DCP fields to PlcValues ?
+                    PlcValue value = PlcValues.of(profinetFrame);
+                    DefaultPlcSubscriptionEvent event = new 
DefaultPlcSubscriptionEvent(
+                        Instant.now(),
+                        Collections.singletonMap(
+                            handle.getName(),
+                            new ResponseItem<>(PlcResponseCode.OK, value)
+                        )
+                    );
+                    consumer.accept(event);
+                }
+            }
+        }
+
         if (profinetFrame.getFrameType() == FrameType.IDENTIFY_RESPONSE) {
             logger.info("Ident response from Profinet device:");
             if (profinetFrame.getFrame() instanceof DcpIdentResponsePDU) {
@@ -113,12 +167,48 @@ public class ProfinetDCPProtocolLogic extends 
Plc4xProtocolBase<EthernetFrame> i
         }
     }
 
+    @Override
+    public CompletableFuture<PlcSubscriptionResponse> 
subscribe(PlcSubscriptionRequest request) {
+        DefaultPlcSubscriptionRequest rq = (DefaultPlcSubscriptionRequest) 
request;
+
+        Map<String, ResponseItem<PlcSubscriptionHandle>> answers = new 
LinkedHashMap<>();
+        DefaultPlcSubscriptionResponse response = new 
DefaultPlcSubscriptionResponse(rq, answers);
+
+        for (String key : rq.getFieldNames()) {
+            DefaultPlcSubscriptionField subscription = 
(DefaultPlcSubscriptionField) rq.getField(key);
+            if (subscription.getPlcSubscriptionType() != 
PlcSubscriptionType.EVENT) {
+                answers.put(key, new 
ResponseItem<>(PlcResponseCode.UNSUPPORTED, null));
+            } else if ((subscription.getPlcField() instanceof 
ProfinetDcpField)) {
+                answers.put(key, new ResponseItem<>(PlcResponseCode.OK,
+                    new ProfinetDCPSubscriptionHandle(this, key, 
(ProfinetDcpField) subscription.getPlcField())
+                ));
+            } else {
+                answers.put(key, new 
ResponseItem<>(PlcResponseCode.INVALID_ADDRESS, null));
+            }
+        }
+
+        return CompletableFuture.completedFuture(response);
+    }
+
+    @Override
+    public PlcConsumerRegistration register(Consumer<PlcSubscriptionEvent> 
consumer, Collection<PlcSubscriptionHandle> handles) {
+        final DefaultPlcConsumerRegistration consumerRegistration = new 
DefaultPlcConsumerRegistration(this, consumer, handles.toArray(new 
DefaultPlcSubscriptionHandle[0]));
+        consumers.put(consumerRegistration, consumer);
+        return consumerRegistration;
+    }
+
+    @Override
+    public void unregister(PlcConsumerRegistration registration) {
+        consumers.remove(registration);
+    }
+
+
     private String addressString(IPv4Address address) {
         return address.getOctet1() + "." + address.getOctet2() + "." + 
address.getOctet3() + "." + address.getOctet4();
     }
 
     @Override
-    public void close(ConversationContext<EthernetFrame> context) {
+    public void close(ConversationContext<BaseEthernetFrame> context) {
 
     }
 
diff --git 
a/sandbox/test-java-profinet-driver/src/main/java/org/apache/plc4x/java/profinet/dcp/protocol/ProfinetDCPSubscriptionHandle.java
 
b/sandbox/test-java-profinet-driver/src/main/java/org/apache/plc4x/java/profinet/dcp/protocol/ProfinetDCPSubscriptionHandle.java
new file mode 100644
index 0000000..2c3b06e
--- /dev/null
+++ 
b/sandbox/test-java-profinet-driver/src/main/java/org/apache/plc4x/java/profinet/dcp/protocol/ProfinetDCPSubscriptionHandle.java
@@ -0,0 +1,54 @@
+/*
+ * 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
+ *
+ *   http://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.dcp.protocol;
+
+import org.apache.plc4x.java.profinet.dcp.field.ProfinetDcpField;
+import org.apache.plc4x.java.profinet.dcp.readwrite.ProfinetFrame;
+import org.apache.plc4x.java.spi.messages.PlcSubscriber;
+import org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionHandle;
+
+public class ProfinetDCPSubscriptionHandle extends 
DefaultPlcSubscriptionHandle {
+
+    private final String name;
+    private final ProfinetDcpField field;
+
+    public ProfinetDCPSubscriptionHandle(PlcSubscriber subscriber, String 
name, ProfinetDcpField field) {
+        super(subscriber);
+        this.name = name;
+        this.field = field;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    boolean matches(ProfinetFrame pdu) {
+        // TODO implement matching logic
+        return false;
+    }
+
+    public ProfinetDcpField getField() {
+        return field;
+    }
+
+    public String toString() {
+        return "ProfinetDCPSubscriptionHandle [service=" + field + "]";
+    }
+
+}

Reply via email to