You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by ld...@apache.org on 2021/03/29 11:56:24 UTC
[plc4x] 04/04: Support for tagged ethernet frames.
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 <lu...@code-house.org>
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 + "]";
+ }
+
+}