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 2021/07/04 15:15:39 UTC
[plc4x] branch feature/profinet-chris updated: - Managed to
implement a first working version of Profinet auto-discovery working.
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch feature/profinet-chris
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/feature/profinet-chris by this push:
new e0bd3cb - Managed to implement a first working version of Profinet auto-discovery working.
e0bd3cb is described below
commit e0bd3cbcc2f78f9faab4b9f1174ebf850b31fbc3
Author: cdutz <ch...@c-ware.de>
AuthorDate: Sun Jul 4 17:15:27 2021 +0200
- Managed to implement a first working version of Profinet auto-discovery working.
---
.../org/apache/plc4x/java/PlcDriverManager.java | 1 -
.../org/apache/plc4x/java/api/Experimental.java | 1 -
.../plc4x/java/api/PlcConnectionExtension.java | 1 -
.../api/exceptions/PlcFieldRangeException.java | 1 -
.../PlcIncompatibleDatatypeException.java | 1 -
.../exceptions/PlcProtocolTimeoutException.java | 34 +--
.../java/api/exceptions/PlcTimeoutException.java | 1 -
.../PlcUnsupportedProtocolException.java | 1 -
.../java/api/model/PlcConsumerRegistration.java | 1 -
...rRegistration.java => PlcDiscoveryHandler.java} | 19 +-
.../plc4x/java/api/model/PlcSubscriptionField.java | 34 +--
.../org/apache/plc4x/java/api/value/PlcValue.java | 1 -
.../plc4x/java/api/value/PlcValueHandler.java | 1 -
plc4j/drivers/profinet/pom.xml | 21 +-
.../apache/plc4x/java/profinet/ProfinetDriver.java | 10 +-
.../ProfinetDiscoveryContext.java} | 11 +-
.../profinet/discovery/ProfinetPlcDiscoverer.java | 228 +++++++++++++++++++++
.../ProfinetDiscoveryLogic.java} | 16 +-
.../plc4x/java/profinet/utils/StaticHelper.java | 4 +
.../resources/protocols/profinet/profinet.mspec | 28 +--
20 files changed, 323 insertions(+), 92 deletions(-)
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/PlcDriverManager.java b/plc4j/api/src/main/java/org/apache/plc4x/java/PlcDriverManager.java
index e3a3fbe..13c3979 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/PlcDriverManager.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/PlcDriverManager.java
@@ -18,7 +18,6 @@
*/
package org.apache.plc4x.java;
-import org.apache.plc4x.java.api.Experimental;
import org.apache.plc4x.java.api.PlcConnection;
import org.apache.plc4x.java.api.authentication.PlcAuthentication;
import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/Experimental.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/Experimental.java
index 8d2d8d3..d43824c 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/Experimental.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/Experimental.java
@@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-
package org.apache.plc4x.java.api;
/**
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/PlcConnectionExtension.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/PlcConnectionExtension.java
index 208a155..1e8ac84 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/PlcConnectionExtension.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/PlcConnectionExtension.java
@@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-
package org.apache.plc4x.java.api;
import org.apache.commons.lang3.NotImplementedException;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcFieldRangeException.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcFieldRangeException.java
index f3908f4..c156f5f 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcFieldRangeException.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcFieldRangeException.java
@@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-
package org.apache.plc4x.java.api.exceptions;
public class PlcFieldRangeException extends PlcRuntimeException {
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcIncompatibleDatatypeException.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcIncompatibleDatatypeException.java
index 64ee10d..dfb2f86 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcIncompatibleDatatypeException.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcIncompatibleDatatypeException.java
@@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-
package org.apache.plc4x.java.api.exceptions;
public class PlcIncompatibleDatatypeException extends PlcRuntimeException {
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcProtocolTimeoutException.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcProtocolTimeoutException.java
index 193e97f..ec7f2e7 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcProtocolTimeoutException.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcProtocolTimeoutException.java
@@ -1,21 +1,21 @@
/*
-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.
-*/
+ * 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.api.exceptions;
public class PlcProtocolTimeoutException extends PlcProtocolException {
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcTimeoutException.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcTimeoutException.java
index ed83dd5..373c8e0 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcTimeoutException.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcTimeoutException.java
@@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-
package org.apache.plc4x.java.api.exceptions;
import java.util.concurrent.TimeUnit;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcUnsupportedProtocolException.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcUnsupportedProtocolException.java
index 2ec7db9..3cb6e3f 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcUnsupportedProtocolException.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcUnsupportedProtocolException.java
@@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-
package org.apache.plc4x.java.api.exceptions;
public class PlcUnsupportedProtocolException extends PlcConnectionException {
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java
index f885564..7ce72ba 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java
@@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-
package org.apache.plc4x.java.api.model;
import java.util.List;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcDiscoveryHandler.java
similarity index 73%
copy from plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java
copy to plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcDiscoveryHandler.java
index f885564..5cb9724 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcDiscoveryHandler.java
@@ -16,21 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
-
package org.apache.plc4x.java.api.model;
-import java.util.List;
-
-/**
- * Represents the registration of one consumer for a given subscription handle.
- * Also provides the means to unsubscribe.
- */
-public interface PlcConsumerRegistration {
-
- Integer getConsumerId();
+import org.apache.plc4x.java.api.messages.PlcDiscoveryItem;
- List<PlcSubscriptionHandle> getSubscriptionHandles();
+public interface PlcDiscoveryHandler {
- void unregister();
+ /**
+ * Callback that gets called as soon as we found a new PlcDiscoveryItem
+ * @param item a PlcDiscoveryItem identifying a newly found resource
+ */
+ void handle(PlcDiscoveryItem item);
}
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionField.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionField.java
index e05c286..3d0dcd7 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionField.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionField.java
@@ -1,21 +1,21 @@
/*
-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.
-*/
+ * 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.api.model;
import org.apache.plc4x.java.api.types.PlcSubscriptionType;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValue.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValue.java
index 47df920..52fbc4e 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValue.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValue.java
@@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-
package org.apache.plc4x.java.api.value;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValueHandler.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValueHandler.java
index 67d6055..3ade947 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValueHandler.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValueHandler.java
@@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-
package org.apache.plc4x.java.api.value;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
diff --git a/plc4j/drivers/profinet/pom.xml b/plc4j/drivers/profinet/pom.xml
index 60fecd6..1188ee9 100644
--- a/plc4j/drivers/profinet/pom.xml
+++ b/plc4j/drivers/profinet/pom.xml
@@ -132,6 +132,12 @@
<artifactId>plc4j-utils-pcap-shared</artifactId>
<version>0.9.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.pcap4j</groupId>
+ <artifactId>pcap4j-core</artifactId>
+ <!-- Override the "provided" scope -->
+ <scope>compile</scope>
+ </dependency>
<dependency>
<groupId>io.netty</groupId>
@@ -153,7 +159,20 @@
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
- <scope>test</scope>
+ <!-- TODO: Just for now -->
+ <scope>compile</scope>
+ </dependency>
+ <!-- TODO: Just for now -->
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <scope>runtime</scope>
+ </dependency>
+ <!-- TODO: Just for now -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <scope>compile</scope>
</dependency>
<dependency>
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java
index 055b147..0a261f7 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java
@@ -23,6 +23,7 @@ import org.apache.plc4x.java.api.messages.PlcDiscoveryRequest;
import org.apache.plc4x.java.api.messages.PlcDiscoveryResponse;
import org.apache.plc4x.java.api.metadata.PlcDriverMetadata;
import org.apache.plc4x.java.profinet.config.ProfinetConfiguration;
+import org.apache.plc4x.java.profinet.discovery.ProfinetPlcDiscoverer;
import org.apache.plc4x.java.profinet.field.ProfinetField;
import org.apache.plc4x.java.profinet.field.ProfinetFieldHandler;
import org.apache.plc4x.java.profinet.protocol.ProfinetProtocolLogic;
@@ -43,7 +44,7 @@ import org.apache.plc4x.java.spi.optimizer.SingleFieldOptimizer;
import java.util.concurrent.CompletableFuture;
import java.util.function.ToIntFunction;
-public class ProfinetDriver extends GeneratedDriverBase<EthernetFrame> implements PlcDiscoverer {
+public class ProfinetDriver extends GeneratedDriverBase<EthernetFrame> {
@Override
public String getProtocolCode() {
@@ -67,7 +68,7 @@ public class ProfinetDriver extends GeneratedDriverBase<EthernetFrame> implement
@Override
public PlcDiscoveryRequest.Builder discoveryRequestBuilder() {
- return new DefaultPlcDiscoveryRequest.Builder(this);
+ return new DefaultPlcDiscoveryRequest.Builder(new ProfinetPlcDiscoverer());
}
@Override
@@ -149,9 +150,4 @@ public class ProfinetDriver extends GeneratedDriverBase<EthernetFrame> implement
return ProfinetField.of(query);
}
- @Override
- public CompletableFuture<PlcDiscoveryResponse> discover(PlcDiscoveryRequest discoveryRequest) {
- return null;
- }
-
}
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/context/ProfinetDiscoveryContext.java
similarity index 77%
copy from plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
copy to plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/context/ProfinetDiscoveryContext.java
index 984d8ff..c3e7d43 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/context/ProfinetDiscoveryContext.java
@@ -16,15 +16,10 @@ 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.utils;
+package org.apache.plc4x.java.profinet.context;
-public class StaticHelper {
+import org.apache.plc4x.java.spi.context.DriverContext;
- public static int stringLength(String str) {
- if (str == null) {
- return 0;
- }
- return str.length();
- }
+public class ProfinetDiscoveryContext implements DriverContext {
}
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java
new file mode 100644
index 0000000..18865c0
--- /dev/null
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java
@@ -0,0 +1,228 @@
+/*
+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.discovery;
+
+import org.apache.plc4x.java.api.messages.PlcDiscoveryRequest;
+import org.apache.plc4x.java.api.messages.PlcDiscoveryResponse;
+import org.apache.plc4x.java.profinet.readwrite.*;
+import org.apache.plc4x.java.profinet.readwrite.io.EthernetFrameIO;
+import org.apache.plc4x.java.profinet.readwrite.types.VirtualLanPriority;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
+import org.apache.plc4x.java.spi.generation.ReadBufferByteBased;
+import org.apache.plc4x.java.spi.generation.WriteBufferByteBased;
+import org.apache.plc4x.java.spi.messages.PlcDiscoverer;
+import org.pcap4j.core.*;
+import org.pcap4j.packet.Dot1qVlanTagPacket;
+import org.pcap4j.packet.EthernetPacket;
+import org.pcap4j.packet.IllegalRawDataException;
+import org.pcap4j.packet.Packet;
+import org.pcap4j.packet.namednumber.EtherType;
+import org.pcap4j.util.LinkLayerAddress;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class ProfinetPlcDiscoverer implements PlcDiscoverer {
+
+ private static final EtherType PN_EtherType = EtherType.getInstance((short) 0x8892);
+
+ private static final String DEVICE_TYPE_NAME = "DEVICE_PROPERTIES_OPTION-1";
+ private static final String DEVICE_NAME_OF_STATION = "DEVICE_PROPERTIES_OPTION-2";
+ private static final String DEVICE_ID = "DEVICE_PROPERTIES_OPTION-3";
+ private static final String DEVICE_ROLE = "DEVICE_PROPERTIES_OPTION-4";
+ private static final String DEVICE_OPTIONS = "DEVICE_PROPERTIES_OPTION-5";
+ private static final String DEVICE_INSTANCE = "DEVICE_PROPERTIES_OPTION-7";
+ private static final String IP_OPTION_IP = "IP_OPTION-2";
+
+ public ProfinetPlcDiscoverer() {
+ }
+
+ @Override
+ public CompletableFuture<PlcDiscoveryResponse> discover(PlcDiscoveryRequest discoveryRequest) {
+ Map<String, DCP_Identify_ResPDU> pnDevices = new HashMap<>();
+ try {
+ for (PcapNetworkInterface dev : Pcaps.findAllDevs()) {
+ if(!dev.isLoopBack() && dev.isRunning()) {
+ for (LinkLayerAddress linkLayerAddress : dev.getLinkLayerAddresses()) {
+ org.pcap4j.util.MacAddress macAddress = (org.pcap4j.util.MacAddress) linkLayerAddress;
+ PcapHandle handle = dev.openLive(65536, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, 10);
+ PcapHandle sendHandle = dev.openLive(65536, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, 10);
+ ExecutorService pool = Executors.newSingleThreadExecutor();
+
+ // Only react on PROFINET DCP packets targeted at our current MAC address.
+ // TODO: Find out how to filter based on the ether frame type ...
+ handle.setFilter(
+ "ether dst " + Pcaps.toBpfString(macAddress),
+ BpfProgram.BpfCompileMode.OPTIMIZE);
+
+ PacketListener listener =
+ packet -> {
+ if(packet instanceof EthernetPacket) {
+ EthernetPacket ethernetPacket = (EthernetPacket) packet;
+ boolean isPnPacket = false;
+ if(ethernetPacket.getPayload() instanceof Dot1qVlanTagPacket) {
+ Dot1qVlanTagPacket vlanPacket = (Dot1qVlanTagPacket) ethernetPacket.getPayload();
+ if(PN_EtherType.equals(vlanPacket.getHeader().getType())) {
+ isPnPacket = true;
+ }
+ } else if(PN_EtherType.equals(ethernetPacket.getHeader().getType())) {
+ isPnPacket = true;
+ }
+
+ // It's a PROFINET packet.
+ if(isPnPacket) {
+ ReadBuffer reader = new ReadBufferByteBased(ethernetPacket.getRawData());
+ try {
+ EthernetFrame ethernetFrame = EthernetFrameIO.staticParse(reader);
+ String sourceMacAddress = toMacAddressString(ethernetFrame.getSource());
+ DCP_PDU pdu;
+ if(ethernetFrame.getPayload() instanceof VirtualLanEthernetFramePayload) {
+ VirtualLanEthernetFramePayload vlefpl = (VirtualLanEthernetFramePayload) ethernetFrame.getPayload();
+ pdu = ((ProfinetEthernetFramePayload) vlefpl.getPayload()).getPdu();
+ } else {
+ pdu = ((ProfinetEthernetFramePayload) ethernetFrame.getPayload()).getPdu();
+ }
+ if(pdu instanceof DCP_Identify_ResPDU) {
+ DCP_Identify_ResPDU identify_resPDU = (DCP_Identify_ResPDU) pdu;
+ if(!pnDevices.containsKey(sourceMacAddress)) {
+ pnDevices.put(sourceMacAddress, identify_resPDU);
+ }
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ };
+ Task t = new Task(handle, listener);
+ pool.execute(t);
+
+ // Construct and send the search request.
+ EthernetFrame identificationRequest = new EthernetFrame(
+ // Pre-Defined PROFINET discovery MAC address
+ new MacAddress(new short[]{0x01, 0x0E, 0xCF, 0x00, 0x00, 0x00}),
+ toPlc4xMacAddress(macAddress),
+ new VirtualLanEthernetFramePayload(VirtualLanPriority.BEST_EFFORT, false, 0,
+ new ProfinetEthernetFramePayload(
+ new DCP_Identify_ReqPDU(
+ new ServiceType(false, false),
+ 1,
+ 256,
+ new DCP_Block[]{
+ new DCP_BlockALLSelector()
+ }))));
+ WriteBufferByteBased buffer = new WriteBufferByteBased(34);
+ EthernetFrameIO.staticSerialize(buffer, identificationRequest);
+ Packet packet = EthernetPacket.newPacket(buffer.getData(), 0, 34);
+ sendHandle.sendPacket(packet);
+ }
+ }
+ }
+ } catch (PcapNativeException | ParseException e) {
+ e.printStackTrace();
+ } catch (NotOpenException e) {
+ e.printStackTrace();
+ } catch (IllegalRawDataException e) {
+ e.printStackTrace();
+ }
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ System.out.println(String.format("Found %d PROFINET devices:", pnDevices.size()));
+ for (DCP_Identify_ResPDU pnDevice : pnDevices.values()) {
+ outputPnDevice(pnDevice);
+ }
+
+ return null;
+ }
+
+ private static MacAddress toPlc4xMacAddress(org.pcap4j.util.MacAddress pcap4jMacAddress) {
+ byte[] address = pcap4jMacAddress.getAddress();
+ return new MacAddress(new short[]{ (short) address[0], (short) address[1], (short) address[2], (short) address[3], (short) address[4], (short) address[5]});
+ }
+
+ private static String toMacAddressString(MacAddress macAddress) {
+ return String.format("%x2:%x2:%x2:%x2:%x2:%x2", macAddress.getAddress()[0], macAddress.getAddress()[1],
+ macAddress.getAddress()[2], macAddress.getAddress()[3], macAddress.getAddress()[4], macAddress.getAddress()[5]);
+ }
+
+ private static void outputPnDevice(DCP_Identify_ResPDU pnDevice) {
+ Map<String, DCP_Block> blocks = new HashMap<>();
+ for (DCP_Block block : pnDevice.getBlocks()) {
+ String blockName = block.getOption().name() + "-" + block.getSuboption().toString();
+ blocks.put(blockName, block);
+ }
+
+ String deviceTypeName = "unknown";
+ if(blocks.containsKey(DEVICE_TYPE_NAME)) {
+ DCP_BlockDevicePropertiesDeviceVendor block = (DCP_BlockDevicePropertiesDeviceVendor) blocks.get(DEVICE_TYPE_NAME);
+ deviceTypeName = new String(block.getDeviceVendorValue());
+ }
+ String deviceName = "unknown";
+ if(blocks.containsKey(DEVICE_NAME_OF_STATION)) {
+ DCP_BlockDevicePropertiesNameOfStation block = (DCP_BlockDevicePropertiesNameOfStation) blocks.get(DEVICE_NAME_OF_STATION);
+ deviceName = new String(block.getNameOfStation());
+ }
+ String ipAddress = "unknown";
+ if(blocks.containsKey(IP_OPTION_IP)) {
+ DCP_BlockIpIpParameter block = (DCP_BlockIpIpParameter) blocks.get(IP_OPTION_IP);
+ ipAddress = String.format("%d.%d.%d.%d", block.getIpAddress()[0], block.getIpAddress()[1], block.getIpAddress()[2], block.getIpAddress()[3]);
+ }
+ System.out.println(String.format("Found '%s' with name '%s' on IP: %s%n\t%s", deviceTypeName, deviceName, ipAddress, pnDevice));
+ }
+
+ private static class Task implements Runnable {
+
+ private PcapHandle handle;
+ private PacketListener listener;
+
+ public Task(PcapHandle handle, PacketListener listener) {
+ this.handle = handle;
+ this.listener = listener;
+ }
+
+ @Override
+ public void run() {
+ try {
+ handle.loop(10, listener);
+ } catch (PcapNativeException e) {
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (NotOpenException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ ProfinetPlcDiscoverer discoverer = new ProfinetPlcDiscoverer();
+ discoverer.discover(null);
+
+ Thread.sleep(10000);
+ }
+
+}
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetDiscoveryLogic.java
similarity index 66%
copy from plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
copy to plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetDiscoveryLogic.java
index 984d8ff..fe886c2 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetDiscoveryLogic.java
@@ -16,15 +16,17 @@ 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.utils;
+package org.apache.plc4x.java.profinet.protocol;
-public class StaticHelper {
+import org.apache.plc4x.java.profinet.readwrite.EthernetFrame;
+import org.apache.plc4x.java.spi.ConversationContext;
+import org.apache.plc4x.java.spi.Plc4xProtocolBase;
+
+public class ProfinetDiscoveryLogic extends Plc4xProtocolBase<EthernetFrame> {
+
+ @Override
+ public void close(ConversationContext<EthernetFrame> context) {
- public static int stringLength(String str) {
- if (str == null) {
- return 0;
- }
- return str.length();
}
}
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
index 984d8ff..2a3351c 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
@@ -27,4 +27,8 @@ public class StaticHelper {
return str.length();
}
+ public static int arrayLength(byte[] arr) {
+ return arr.length;
+ }
+
}
diff --git a/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec b/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
index 90ad1af..d9d2138 100644
--- a/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
+++ b/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
@@ -49,7 +49,7 @@
// 4.3.1.3.5 (Page 95ff)
[simple uint 16 'responseDelayFactorOrPadding']
// 4.3.1.3.4 (Page 95)
- [implicit uint 16 'dcpDataLength' 'lengthInBytes - 10']
+ [implicit uint 16 'dcpDataLength' 'lengthInBytes - 12']
[typeSwitch 'frameId','serviceId','serviceType.response'
////////////////////////////////////////////////////////////////////////////
// Multicast (Well theoretically)
@@ -108,7 +108,7 @@
[discriminatedType 'DCP_Block'
[discriminator BlockOptions 'option' ]
[discriminator uint 8 'suboption' ]
- [implicit uint 16 'blockLength' 'lengthInBytes' ]
+ [implicit uint 16 'blockLength' 'lengthInBytes - 4' ]
[typeSwitch 'option','suboption'
////////////////////////////////////////////////////////////////////////////
@@ -139,17 +139,17 @@
// DEVICE_PROPERTIES_OPTION
////////////////////////////////////////////////////////////////////////////
- ['DEVICE_PROPERTIES_OPTION','1' DCP_BlockDevicePropertiesDeviceVendor
+ ['DEVICE_PROPERTIES_OPTION','1' DCP_BlockDevicePropertiesDeviceVendor [uint 16 'blockLength']
[reserved uint 16 '0x0000' ]
// TODO: Figure out how to do this correctly.
- [simple string '-1' 'deviceVendorValue' ]
- [padding uint 8 'pad' '0x00' 'STATIC_CALL("org.apache.plc4x.java.profinet.utils.StaticHelper.stringLength", deviceVendorValue) % 2' ]
+ [array byte 'deviceVendorValue' count 'blockLength-2' ]
+ [padding uint 8 'pad' '0x00' 'STATIC_CALL("org.apache.plc4x.java.profinet.utils.StaticHelper.arrayLength", deviceVendorValue) % 2']
]
- ['DEVICE_PROPERTIES_OPTION','2' DCP_BlockDevicePropertiesNameOfStation
+ ['DEVICE_PROPERTIES_OPTION','2' DCP_BlockDevicePropertiesNameOfStation [uint 16 'blockLength']
[reserved uint 16 '0x0000' ]
// TODO: Figure out how to do this correctly.
- [simple string '-1' 'nameOfStation' ]
- [padding uint 8 'pad' '0x00' 'STATIC_CALL("org.apache.plc4x.java.profinet.utils.StaticHelper.stringLength", nameOfStation) % 2' ]
+ [array byte 'nameOfStation' count 'blockLength-2' ]
+ [padding uint 8 'pad' '0x00' 'STATIC_CALL("org.apache.plc4x.java.profinet.utils.StaticHelper.arrayLength", nameOfStation) % 2']
]
['DEVICE_PROPERTIES_OPTION','3' DCP_BlockDevicePropertiesDeviceId
[reserved uint 16 '0x0000' ]
@@ -162,16 +162,17 @@
[simple bit 'pnioMultidevive' ]
[simple bit 'pnioController' ]
[simple bit 'pnioDevice' ]
+ [reserved uint 8 '0x00' ]
]
// Contains a list of option combinations the device supports.
['DEVICE_PROPERTIES_OPTION','5' DCP_BlockDevicePropertiesDeviceOptions [uint 16 'blockLength']
[reserved uint 16 '0x0000' ]
[array SupportedDeviceOption 'supportedOptions' length 'blockLength - 2' ]
]
- ['DEVICE_PROPERTIES_OPTION','6' DCP_BlockDevicePropertiesAliasName
+ ['DEVICE_PROPERTIES_OPTION','6' DCP_BlockDevicePropertiesAliasName [uint 16 'blockLength']
[reserved uint 16 '0x0000' ]
- [simple string '-1' 'aliasNameValue' ]
- [padding uint 8 'pad' '0x00' 'STATIC_CALL("org.apache.plc4x.java.profinet.utils.StaticHelper.stringLength", aliasNameValue) % 2' ]
+ [array byte 'aliasNameValue' count 'blockLength-2' ]
+ [padding uint 8 'pad' '0x00' 'STATIC_CALL("org.apache.plc4x.java.profinet.utils.StaticHelper.arrayLength", aliasNameValue) % 2']
]
['DEVICE_PROPERTIES_OPTION','7' DCP_BlockDevicePropertiesDeviceInstance
[reserved uint 16 '0x0000' ]
@@ -328,9 +329,10 @@
['0xFF' ALL_SELECTOR_OPTION]
]
+// https://de.wikipedia.org/wiki/IEEE_802.1p
[enum uint 3 'VirtualLanPriority' [string '2' 'acronym']
- ['0x0' BACKGROUND ['BK' ]]
- ['0x1' BEST_EFFORT ['BE' ]]
+ ['0x0' BEST_EFFORT ['BE' ]]
+ ['0x1' BACKGROUND ['BK' ]]
['0x2' EXCELLENT_EFFORT ['EE' ]]
['0x3' CRITICAL_APPLICATIONS ['CA' ]]
['0x4' VIDEO ['VI' ]]