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 2020/01/26 17:31:59 UTC

[plc4x] branch develop updated: - Updated Dominik's design proposal for the start page.

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

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


The following commit(s) were added to refs/heads/develop by this push:
     new 88636d4  - Updated Dominik's design proposal for the start page.
88636d4 is described below

commit 88636d44f10027d6ecc70174cca3ae21d39fc4f8
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Sun Jan 26 18:31:42 2020 +0100

    - Updated Dominik's design proposal for the start page.
---
 .../resources/protocols/bacnetip/bacnetip.mspec    |  14 +-
 .../plc4x/java/bacnetip/PassiveBacNetIpDriver.java |  15 ++
 .../PassiveBacNetIpConfiguration.java              |  12 +
 .../apache/plc4x/java/bacnetip/ede/EdeParser.java  |  31 +++
 .../plc4x/java/bacnetip/ede/model/EdeModel.java    |  22 ++
 .../plc4x/java/bacnetip/field/BacNetIpField.java   |  52 +++-
 .../protocol/PassiveBacNetIpProtocolLogic.java     | 182 ++++++++++++-
 .../src/test/resources/logback.xml                 |  36 +++
 src/site/asciidoc/index.adoc                       | 283 +++++++++++++++++----
 src/site/resources/images/background-index-3.png   | Bin 0 -> 1258500 bytes
 10 files changed, 577 insertions(+), 70 deletions(-)

diff --git a/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec b/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
index 84113aa..eb001e9 100644
--- a/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
+++ b/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
@@ -494,12 +494,12 @@
     [simple        uint 4 'typeOrTagNumber']
     [simple        uint 1 'contextSpecificTag']
     [simple        uint 3 'lengthValueType']
-    [optional      uint 8 'extTagNumber' 'typeOrTagNumber == 15']
-    [optional      uint 8 'extLength' 'lengthValueType == 5']
-    [array         uint 8 'propertyIdentifier' length '(lengthValueType == 5) ? extLength : lengthValueType']
-    [const         uint 8 'openTag' '0x2e']
+    [optional      uint 8 'extTagNumber'        'typeOrTagNumber == 15']
+    [optional      uint 8 'extLength'           'lengthValueType == 5']
+    [array         uint 8 'propertyIdentifier'  length          '(lengthValueType == 5) ? extLength : lengthValueType']
+    [const         uint 8 'openTag'             '0x2e']
     [simple        BACnetTag 'value']
-    [const         uint 8 'closingTag' '0x2f']
+    [const         uint 8 'closingTag'          '0x2f']
 ]
 
 [discriminatedType 'BACnetTag'
@@ -520,10 +520,10 @@
             [array int 8 'data' length '(lengthValueType == 5) ? extLength : lengthValueType']
         ]
         ['0','0x4' BACnetTagApplicationReal [uint 3 'lengthValueType', uint 8 'extLength']
-            [array int 8 'data' length '(lengthValueType == 5) ? extLength : lengthValueType']
+            [simple float 8.23 'value']
         ]
         ['0','0x5' BACnetTagApplicationDouble [uint 3 'lengthValueType', uint 8 'extLength']
-            [array int 8 'data' length '(lengthValueType == 5) ? extLength : lengthValueType']
+            [simple float 11.52 'value']
         ]
         ['0','0x6' BACnetTagApplicationOctetString
         ]
diff --git a/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/PassiveBacNetIpDriver.java b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/PassiveBacNetIpDriver.java
index a0852d6..a4c472c 100644
--- a/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/PassiveBacNetIpDriver.java
+++ b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/PassiveBacNetIpDriver.java
@@ -60,6 +60,21 @@ public class PassiveBacNetIpDriver extends GeneratedDriverBase<BVLC> {
     }
 
     @Override
+    protected boolean canRead() {
+        return false;
+    }
+
+    @Override
+    protected boolean canWrite() {
+        return false;
+    }
+
+    @Override
+    protected boolean canSubscribe() {
+        return true;
+    }
+
+    @Override
     protected BacNetIpFieldHandler getFieldHandler() {
         return new BacNetIpFieldHandler();
     }
diff --git a/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/configuration/PassiveBacNetIpConfiguration.java b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/configuration/PassiveBacNetIpConfiguration.java
index 6af5437..76519f5 100644
--- a/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/configuration/PassiveBacNetIpConfiguration.java
+++ b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/configuration/PassiveBacNetIpConfiguration.java
@@ -19,6 +19,7 @@ under the License.
 package org.apache.plc4x.java.bacnetip.configuration;
 
 import org.apache.plc4x.java.spi.configuration.Configuration;
+import org.apache.plc4x.java.spi.configuration.annotations.ConfigurationParameter;
 import org.apache.plc4x.java.transport.pcap.PcapTransportConfiguration;
 import org.apache.plc4x.java.transport.rawsocket.RawSocketTransportConfiguration;
 import org.apache.plc4x.java.transport.udp.UdpTransportConfiguration;
@@ -27,6 +28,17 @@ import org.pcap4j.packet.Packet;
 
 public class PassiveBacNetIpConfiguration implements Configuration, UdpTransportConfiguration, RawSocketTransportConfiguration, PcapTransportConfiguration {
 
+    @ConfigurationParameter("ede-file-path")
+    public String edeFilePath;
+
+    public String getEdeFilePath() {
+        return edeFilePath;
+    }
+
+    public void setEdeFilePath(String edeFilePath) {
+        this.edeFilePath = edeFilePath;
+    }
+
     @Override
     public int getDefaultPort() {
         return 47808;
diff --git a/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/ede/EdeParser.java b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/ede/EdeParser.java
new file mode 100644
index 0000000..7debb84
--- /dev/null
+++ b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/ede/EdeParser.java
@@ -0,0 +1,31 @@
+/*
+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.bacnetip.ede;
+
+import org.apache.plc4x.java.bacnetip.ede.model.EdeModel;
+
+import java.io.File;
+
+public class EdeParser {
+
+    public EdeModel parse(File knxprojFile) {
+        return null;
+    }
+
+}
diff --git a/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/ede/model/EdeModel.java b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/ede/model/EdeModel.java
new file mode 100644
index 0000000..6151fa2
--- /dev/null
+++ b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/ede/model/EdeModel.java
@@ -0,0 +1,22 @@
+/*
+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.bacnetip.ede.model;
+
+public class EdeModel {
+}
diff --git a/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/field/BacNetIpField.java b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/field/BacNetIpField.java
index 8656172..7432827 100644
--- a/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/field/BacNetIpField.java
+++ b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/field/BacNetIpField.java
@@ -18,6 +18,7 @@ under the License.
 */
 package org.apache.plc4x.java.bacnetip.field;
 
+import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.model.PlcField;
 
@@ -27,10 +28,14 @@ import java.util.regex.Pattern;
 public class BacNetIpField implements PlcField {
 
     private static final Pattern ADDRESS_PATTERN =
-        Pattern.compile("^N(?<fileNumber>\\d{1,7}):(?<elementNumber>\\d{1,7})(/(?<bitNumber>\\d{1,7}))?:(?<dataType>[a-zA-Z_]+)(\\[(?<size>\\d+)])?");
+        Pattern.compile("^(?<deviceIdentifier>(\\d|\\*))/(?<objectType>(\\d|\\*))/(?<objectInstance>(\\d|\\*))");
 
-    public BacNetIpField() {
-    }
+    public static final int INT_WILDCARD = -1;
+    public static final long LONG_WILDCARD = -1;
+
+    private final long deviceIdentifier;
+    private final int objectType;
+    private final long objectInstance;
 
     public static boolean matches(String fieldString) {
         return ADDRESS_PATTERN.matcher(fieldString).matches();
@@ -39,9 +44,48 @@ public class BacNetIpField implements PlcField {
     public static BacNetIpField of(String fieldString) {
         Matcher matcher = ADDRESS_PATTERN.matcher(fieldString);
         if(matcher.matches()) {
-            return new BacNetIpField();
+            long deviceIdentifier = matcher.group("deviceIdentifier").equals("*") ?
+                LONG_WILDCARD : Long.parseLong(matcher.group("deviceIdentifier"));
+            int objectType = matcher.group("objectType").equals("*") ?
+                INT_WILDCARD : Integer.parseInt(matcher.group("objectType"));
+            long objectInstance = matcher.group("objectInstance").equals("*") ?
+                LONG_WILDCARD : Long.parseLong(matcher.group("objectInstance"));
+            return new BacNetIpField(deviceIdentifier, objectType, objectInstance);
         }
         throw new PlcInvalidFieldException("Unable to parse address: " + fieldString);
     }
 
+    public BacNetIpField(long deviceIdentifier, int objectType, long objectInstance) {
+        this.deviceIdentifier = deviceIdentifier;
+        this.objectType = objectType;
+        this.objectInstance = objectInstance;
+    }
+
+    public long getDeviceIdentifier() {
+        return deviceIdentifier;
+    }
+
+    public int getObjectType() {
+        return objectType;
+    }
+
+    public long getObjectInstance() {
+        return objectInstance;
+    }
+
+    public boolean matches(BacNetIpField otherField) {
+        return ((deviceIdentifier == LONG_WILDCARD) || (deviceIdentifier == otherField.deviceIdentifier)) &&
+            ((objectType == INT_WILDCARD) || (objectType == otherField.objectType)) &&
+            ((objectInstance == LONG_WILDCARD) || (objectInstance == otherField.objectInstance));
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this)
+            .append("deviceIdentifier", deviceIdentifier)
+            .append("objectType", objectType)
+            .append("objectInstance", objectInstance)
+            .toString();
+    }
+
 }
diff --git a/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/protocol/PassiveBacNetIpProtocolLogic.java b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/protocol/PassiveBacNetIpProtocolLogic.java
index fa37a07..0f2cf9b 100644
--- a/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/protocol/PassiveBacNetIpProtocolLogic.java
+++ b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/protocol/PassiveBacNetIpProtocolLogic.java
@@ -18,19 +18,65 @@ under the License.
 */
 package org.apache.plc4x.java.bacnetip.protocol;
 
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+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.value.PlcValue;
 import org.apache.plc4x.java.bacnetip.configuration.PassiveBacNetIpConfiguration;
-import org.apache.plc4x.java.bacnetip.readwrite.BVLC;
+import org.apache.plc4x.java.bacnetip.ede.EdeParser;
+import org.apache.plc4x.java.bacnetip.ede.model.EdeModel;
+import org.apache.plc4x.java.bacnetip.field.BacNetIpField;
+import org.apache.plc4x.java.bacnetip.readwrite.*;
 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.ReadBuffer;
+import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionEvent;
+import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionResponse;
+import org.apache.plc4x.java.spi.messages.InternalPlcSubscriptionRequest;
+import org.apache.plc4x.java.spi.messages.PlcSubscriber;
+import org.apache.plc4x.java.spi.model.DefaultPlcConsumerRegistration;
+import org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionHandle;
+import org.apache.plc4x.java.spi.model.InternalPlcSubscriptionHandle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-public class PassiveBacNetIpProtocolLogic extends Plc4xProtocolBase<BVLC> implements HasConfiguration<PassiveBacNetIpConfiguration> {
+import java.io.File;
+import java.time.Instant;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
 
-    private PassiveBacNetIpConfiguration configuration;
+public class PassiveBacNetIpProtocolLogic extends Plc4xProtocolBase<BVLC> implements HasConfiguration<PassiveBacNetIpConfiguration>, PlcSubscriber {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(PassiveBacNetIpProtocolLogic.class);
+
+    private EdeModel edeModel;
+
+    private Map<Integer, Consumer<PlcSubscriptionEvent>> consumerIdMap = new ConcurrentHashMap<>();
 
     @Override
     public void setConfiguration(PassiveBacNetIpConfiguration configuration) {
-        this.configuration = configuration;
+        if (configuration.edeFilePath != null) {
+            File edeFile = new File(configuration.edeFilePath);
+            if (edeFile.exists() && edeFile.isFile()) {
+                edeModel = new EdeParser().parse(edeFile);
+            } else {
+                throw new PlcRuntimeException(String.format(
+                    "File specified with 'ede-file-path' does not exist or is not a file: '%s'",
+                    configuration.edeFilePath));
+            }
+        }
     }
 
     @Override
@@ -40,8 +86,132 @@ public class PassiveBacNetIpProtocolLogic extends Plc4xProtocolBase<BVLC> implem
 
     @Override
     protected void decode(ConversationContext<BVLC> context, BVLC msg) throws Exception {
-        System.out.println(msg);
-        super.decode(context, msg);
+        NPDU npdu = null;
+        if(msg instanceof BVLCOriginalUnicastNPDU) {
+            BVLCOriginalUnicastNPDU bvlcOriginalUnicastNPDU = (BVLCOriginalUnicastNPDU) msg;
+            npdu = bvlcOriginalUnicastNPDU.getNpdu();
+        } else if (msg instanceof BVLCForwardedNPDU) {
+            BVLCForwardedNPDU bvlcForwardedNPDU = (BVLCForwardedNPDU) msg;
+            npdu = bvlcForwardedNPDU.getNpdu();
+        } else if (msg instanceof BVLCOriginalBroadcastNPDU) {
+            BVLCOriginalBroadcastNPDU bvlcOriginalBroadcastNPDU = (BVLCOriginalBroadcastNPDU) msg;
+            npdu = bvlcOriginalBroadcastNPDU.getNpdu();
+        }
+
+        if(npdu != null) {
+            if(npdu.getApdu() instanceof APDUConfirmedRequest) {
+                APDUConfirmedRequest apduConfirmedRequest = (APDUConfirmedRequest) npdu.getApdu();
+                final BACnetConfirmedServiceRequest serviceRequest = apduConfirmedRequest.getServiceRequest();
+                // A value change subscription event.
+                if(serviceRequest instanceof BACnetConfirmedServiceRequestConfirmedCOVNotification) {
+                    BACnetConfirmedServiceRequestConfirmedCOVNotification valueChange =
+                        (BACnetConfirmedServiceRequestConfirmedCOVNotification) serviceRequest;
+
+                    long deviceIdentifier = valueChange.getMonitoredObjectInstanceNumber();
+                    int objectType = valueChange.getIssueConfirmedNotificationsType();
+                    long objectInstance = valueChange.getIssueConfirmedNotificationsInstanceNumber();
+                    BacNetIpField curField = new BacNetIpField(deviceIdentifier, objectType, objectInstance);
+
+                    System.out.println("Value change for " + curField.toString());
+
+                    for (BACnetTagWithContent notification : valueChange.getNotifications()) {
+                        if(notification.getPropertyIdentifier()[0] == (short) 0x55) {
+                            final BACnetTag baCnetTag = notification.getValue();
+                            if(baCnetTag instanceof BACnetTagApplicationReal) {
+                                System.out.println(baCnetTag);
+                            }
+                        }
+                        // Use the information in the edeModel to enrich the information.
+                        if(edeModel != null) {
+                            // TODO: Implement.
+                        }
+                        // Else just output the information without enriching it.
+                        else {
+                            // TODO: Implement.
+                        }
+                    }
+                }
+                // Someone read a value.
+                else if(serviceRequest instanceof BACnetConfirmedServiceRequestReadProperty) {
+                    // Ignore this ...
+                }
+                // Someone wrote a value.
+                else if(serviceRequest instanceof BACnetConfirmedServiceRequestWriteProperty) {
+                    // Ignore this ...
+                } else if(serviceRequest instanceof BACnetConfirmedServiceRequestSubscribeCOV) {
+                    // Ignore this ...
+                } else {
+                    LOGGER.debug(String.format("Unexpected ConfirmedServiceRequest type: %s", serviceRequest.getClass().getName()));
+                }
+            } else if(npdu.getApdu() instanceof APDUUnconfirmedRequest) {
+                APDUUnconfirmedRequest unconfirmedRequest = (APDUUnconfirmedRequest) npdu.getApdu();
+                final BACnetUnconfirmedServiceRequest serviceRequest = unconfirmedRequest.getServiceRequest();
+                if(serviceRequest instanceof BACnetUnconfirmedServiceRequestWhoHas) {
+                    // Ignore this ...
+                } else if(serviceRequest instanceof BACnetUnconfirmedServiceRequestWhoIs){
+                    // Ignore this ...
+                } else if(serviceRequest instanceof BACnetUnconfirmedServiceRequestIAm){
+                    // Ignore this ...
+                } else if(serviceRequest instanceof BACnetUnconfirmedServiceRequestUnconfirmedPrivateTransfer){
+                    // Ignore this ...
+                } else {
+                    LOGGER.debug(String.format("Unexpected UnconfirmedServiceRequest type: %s", serviceRequest.getClass().getName()));
+                }
+            } else if(npdu.getApdu() instanceof APDUError) {
+                APDUError apduError = (APDUError) npdu.getApdu();
+            } else if(npdu.getApdu() instanceof APDUSimpleAck) {
+                // Ignore this ...
+            } else if(npdu.getApdu() instanceof APDUComplexAck) {
+                // Ignore this ...
+            } else if((npdu.getApdu() == null) && (npdu.getNlm() != null)){
+                // "Who is router?" & "I am router" messages.
+                // Ignore this ...
+            } else {
+                LOGGER.debug(String.format("Unexpected NPDU type: %s", npdu.getClass().getName()));
+            }
+        }
+    }
+
+    @Override
+    public CompletableFuture<PlcSubscriptionResponse> subscribe(PlcSubscriptionRequest subscriptionRequest) {
+        Map<String, Pair<PlcResponseCode, PlcSubscriptionHandle>> values = new HashMap<>();
+        for (String fieldName : subscriptionRequest.getFieldNames()) {
+            values.put(fieldName, new ImmutablePair<>(PlcResponseCode.OK, new DefaultPlcSubscriptionHandle(this)));
+        }
+        return CompletableFuture.completedFuture(
+            new DefaultPlcSubscriptionResponse((InternalPlcSubscriptionRequest) subscriptionRequest, values));
     }
 
+    @Override
+    public PlcConsumerRegistration register(Consumer<PlcSubscriptionEvent> consumer, Collection<PlcSubscriptionHandle> collection) {
+        final DefaultPlcConsumerRegistration consumerRegistration =
+            new DefaultPlcConsumerRegistration(this, consumer, collection.toArray(new InternalPlcSubscriptionHandle[0]));
+        consumerIdMap.put(consumerRegistration.getConsumerHash(), consumer);
+        return consumerRegistration;
+    }
+
+    @Override
+    public void unregister(PlcConsumerRegistration plcConsumerRegistration) {
+        DefaultPlcConsumerRegistration consumerRegistration = (DefaultPlcConsumerRegistration) plcConsumerRegistration;
+        consumerIdMap.remove(consumerRegistration.getConsumerHash());
+    }
+
+    protected void publishEvent(String name, PlcValue plcValue) {
+        // Create a subscription event from the input.
+        final PlcSubscriptionEvent event = new DefaultPlcSubscriptionEvent(Instant.now(),
+            Collections.singletonMap(name, Pair.of(PlcResponseCode.OK, plcValue)));
+
+        // Send the subscription event to all listeners.
+        for (Consumer<PlcSubscriptionEvent> consumer : consumerIdMap.values()) {
+            consumer.accept(event);
+        }
+    }
+
+    /*protected PlcValue toPlcValue(BACnetTag tag) {
+        if(tag instanceof BACnetTagApplicationReal) {
+            BACnetTagApplicationReal baCnetTagApplicationReal = (BACnetTagApplicationReal) tag;
+            baCnetTagApplicationReal.getData();
+        }
+    }*/
+
 }
diff --git a/sandbox/test-java-bacnetip-driver/src/test/resources/logback.xml b/sandbox/test-java-bacnetip-driver/src/test/resources/logback.xml
new file mode 100644
index 0000000..27d40c0
--- /dev/null
+++ b/sandbox/test-java-bacnetip-driver/src/test/resources/logback.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+  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.
+
+-->
+<configuration xmlns="http://ch.qos.logback/xml/ns/logback"
+               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+               xsi:schemaLocation="http://ch.qos.logback/xml/ns/logback https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd">
+
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <!-- encoders are assigned the type
+         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
+    <encoder>
+      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+    </encoder>
+  </appender>
+
+  <root level="info">
+    <appender-ref ref="STDOUT" />
+  </root>
+
+</configuration>
\ No newline at end of file
diff --git a/src/site/asciidoc/index.adoc b/src/site/asciidoc/index.adoc
index faf85b6..60860e9 100644
--- a/src/site/asciidoc/index.adoc
+++ b/src/site/asciidoc/index.adoc
@@ -18,60 +18,237 @@
 :icons: font
 
 ++++
-    <header class="bg-light text-white align-middle" style="height: 300px;">
-        <div class="container text-center pt-5">
-            <h1>The universal protocol adapter for Industrial IoT</h1>
-            <p class="lead">Building bridges between IT and OT</p>
-        </div>
-    </header>
-    <section id="no-retrofit" class="align-middle" style="height: 300px;">
-        <div class="container text-center pt-5">
-            <div class="row">
-                <div class="col-lg-8 mx-auto">
-                    <h2>Connect your shopfloor assets without having to retrofit them</h2>
-                    <p class="lead">In contrast to other approaches, Apache PLC4X lets you connect your industrial assets without the need to modify them.</p>
-                </div>
-            </div>
-        </div>
-    </section>
-    <section id="secure" class="bg-light align-middle" style="height: 300px;">
-        <div class="container text-center pt-5">
-            <div class="row">
-                <div class="col-lg-8 mx-auto">
-                    <h2>Secure by design</h2>
-                    <p class="lead">Not only are Apache PLC4X drivers implemented with security in mind, but our passive-mode drivers also bring you a guarantee of freedom from side-effects, without the need to pay for validated software.</p>
-                </div>
-            </div>
-        </div>
-    </section>
-    <section id="performant" class="align-middle" style="height: 300px;">
-        <div class="container text-center pt-5">
-            <div class="row">
-                <div class="col-lg-8 mx-auto">
-                    <h2>Get the performance you need</h2>
-                    <p class="lead">Most approaches like OPC-UA currently don't deliver the performance needed for machine learning, deep learning and AI. Apache PLC4X allows you to get the data volumes in the resolutions needed, without stressing out your industial hardware.</p>
+<div class="jumbotron jumbotron-fluid teaser-img">
+    <div class="row" style="align-items:center;z-index:2;position:relative;">
+        <div class="col-12 col-lg-2"></div>
+    <div class="col-12 col-lg-8" style="display:flex;justify-content: center">
+        <div class="teaser-box">
+            <div class="row margin-rl-0">
+                <div class="col-md-12">
+                    <div class="margin-rl-auto">
+                        <img src="images/apache_plc4x_logo.png"  alt="Apache PLC4X" class="plc4x-logo center"/>
+                    </div>
+                    <h3 style="text-align:center;">
+                        <div class="plc4x-headline" style="text-align:center;">The universal
+                            protocol adapter for
+                            Industrial IoT
+                         </div>
+                     </h3>
+                    <div class="apache-teaser center text-center">PLC4X is a set of libraries
+                        for
+                        communicating with
+                        industrial
+                        programmable logic controllers (PLCs) using a variety of protocols but with a shared API.</div>
+                    <div class="center text-center">
+                    <a href="users/plc4j/gettingstarted.html"
+                       class="plc4x-button plc4x-button-large plc4x-button-primary text-center"><i
+                            class="fas fa-rocket"></i> Get started
+                    </a>
+                    </div>
                 </div>
             </div>
         </div>
-    </section>
-    <section id="costs" class="bg-light align-middle" style="height: 300px;">
-        <div class="container text-center pt-5">
-            <div class="row">
-                <div class="col-lg-8 mx-auto">
-                    <h2>No license-costs, no restrictive licenses</h2>
-                    <p class="lead">Being open-source, Apache PLC4X is <b>free of charge</b>. Start experimenting without worrying about license costs or shady license agreements. The Apache 2.0 is one of the world's <b>most trusted and adopted</b> open-source licenses out there.</p>
-                </div>
-            </div>
-        </div>
-    </section>
-    <section id="with-support" class="align-middle" style="height: 300px;">
-        <div class="container text-center pt-5">
-            <div class="row">
-                <div class="col-lg-8 mx-auto">
-                    <h2>Get the commercial support you need</h2>
-                    <p class="lead">Just because you can download and use Apache PLC4X for free doesn't mean that you're left on your own. Some of our community members comapnies can also provide you with the <b>commercial support</b> you need.</p>
-                </div>
-            </div>
-        </div>
-    </section>
+    </div>
+        <div class="col-12 col-lg-2"></div>
+    </div>
+</div>
+
+       <section id="no-retrofit" class="section-highlight section-highlight-primary">
+           <div class="container text-center">
+               <div class="row">
+                   <div class="col-lg-12 mx-auto">
+                       <i class="fas fa-plug fa-7x highlight-icon highlight-icon-primary"></i>
+                       <h2 class="section-highlight-text-primary">Connect your shopfloor assets without retrofit.</h2>
+                       <p class="lead c-white">In contrast to other approches, Apache PLC4X lets you connect your industrial assets without needing to modify them.</p>
+                   </div>
+               </div>
+           </div>
+       </section>
+       <section id="no-retrofit" class="section-highlight section-highlight-secondary mb-5">
+           <div class="container text-center">
+               <div class="row">
+                   <div class="col-lg-12 mx-auto">
+                       <h2 class="section-highlight-text-secondary">Integrations.</h2>
+                       <p class="lead">PLC4X comes with many built-in integrations to further process your asset data. </p>
+                       <div id="integrationCarousel" class="carousel slide" data-ride="carousel">
+                           <div class="carousel-inner">
+                               <div class="carousel-item active">
+                                   <div class="col-md-4">
+                                       <div class="card h-100 p-5 justify-content-center"
+                                            onclick="location.href='https://calcite.apache.org';" style="cursor:pointer;">
+                                           <div class="d-flex align-items-center justify-content-center h-100">
+                                               <img src="images/apache_calcite_logo.svg" alt="Card image cap">
+                                           </div>
+                                           <div class="card-body">
+                                               <h5 class="card-title"><b>Apache Calcite</b></h5>
+                                           </div>
+                                       </div>
+                                   </div>
+                               </div>
+                               <div class="carousel-item">
+                                   <div class="col-md-4">
+                                       <div class="card h-100 p-5 justify-content-center"
+                                            onclick="location.href='https://camel.apache.org';" style="cursor:pointer;">
+                                           <div class="d-flex align-items-center justify-content-center h-100">
+                                               <img src="images/apache_camel_logo.png" alt="Card image cap">
+                                           </div>
+                                           <div class="card-body">
+                                               <h5 class="card-title"><b>Apache Camel</b></h5>
+                                           </div>
+                                       </div>
+                                   </div>
+                               </div>
+                               <div class="carousel-item">
+                                   <div class="col-md-4">
+                                       <div class="card h-100 p-5 justify-content-center"
+                                            onclick="location.href='https://edgent.apache.org';" style="cursor:pointer;">
+                                           <div class="d-flex align-items-center justify-content-center h-100">
+                                               <img src="images/apache_edgent_logo.png" alt="Card image cap">
+                                           </div>
+                                           <div class="card-body">
+                                               <h5 class="card-title"><b>Apache Edgent</b></h5>
+                                           </div>
+                                       </div>
+                                   </div>
+                               </div>
+                               <div class="carousel-item">
+                                   <div class="col-md-4">
+                                       <div class="card h-100 p-5 justify-content-center"
+                                            onclick="location.href='https://iotdb.apache.org';" style="cursor:pointer;">
+                                           <div class="d-flex align-items-center justify-content-center h-100">
+                                               <img src="images/apache_iotdb_logo.png" alt="Card image cap">
+                                           </div>
+                                           <div class="card-body">
+                                               <h5 class="card-title"><b>Apache IoTDB (incubating)</b></h5>
+                                           </div>
+                                       </div>
+                                   </div>
+                               </div>
+                               <div class="carousel-item">
+                                   <div class="col-md-4">
+                                       <div class="card h-100 p-5 justify-content-center"
+                                            onclick="location.href='https://kafka.apache.org';" style="cursor:pointer;">
+                                           <div class="d-flex align-items-center justify-content-center h-100">
+                                               <img src="images/apache_kafka_logo.png" alt="Card image cap">
+                                           </div>
+                                           <div class="card-body">
+                                               <h5 class="card-title"><b>Apache Kafka</b></h5>
+                                           </div>
+                                       </div>
+                                   </div>
+                               </div>
+                               <div class="carousel-item">
+                                   <div class="col-md-4">
+                                       <div class="card h-100 p-5 justify-content-center"
+                                            onclick="location.href='https://nifi.apache.org';" style="cursor:pointer;">
+                                           <div class="d-flex align-items-center justify-content-center h-100">
+                                               <img src="images/apache_nifi_logo.svg" alt="Card image cap">
+                                           </div>
+                                           <div class="card-body">
+                                               <h5 class="card-title"><b>Apache Nifi</b></h5>
+                                           </div>
+                                       </div>
+                                   </div>
+                               </div>
+                               <div class="carousel-item">
+                                   <div class="col-md-4">
+                                       <div class="card h-100 p-5 justify-content-center"
+                                            onclick="location.href='https://streampipes.apache.org';"
+                                            style="cursor:pointer;">
+                                           <div class="d-flex align-items-center justify-content-center h-100">
+                                               <img src="images/apache_streampipes_logo.png" alt="Card image cap">
+                                           </div>
+                                           <div class="card-body">
+                                               <h5 class="card-title"><b>Apache StreamPipes (incubating)</b></h5>
+                                           </div>
+                                       </div>
+                                   </div>
+                               </div>
+                               <div class="carousel-item">
+                                   <div class="col-md-4">
+                                       <div class="card h-100 p-5 justify-content-center"
+                                            onclick="location.href='https://www.eclipse.org/ditto/';"
+                                            style="cursor:pointer;">
+                                           <div class="d-flex align-items-center justify-content-center h-100">
+                                               <img src="images/eclipse_ditto_logo.png" alt="Card image cap">
+                                           </div>
+                                           <div class="card-body">
+                                               <h5 class="card-title"><b>Eclipse Ditto</b></h5>
+                                           </div>
+                                       </div>
+                                   </div>
+                               </div>
+                               <div class="carousel-item">
+                                   <div class="col-md-4">
+                                       <div class="card h-100 p-5 justify-content-center"
+                                            onclick="location.href='https://www.elastic.co/products/logstash';"
+                                            style="cursor:pointer;">
+                                           <div class="d-flex align-items-center justify-content-center h-100">
+                                               <img src="images/elastic_logstash_logo.png" alt="Card image cap">
+                                           </div>
+                                           <div class="card-body">
+                                               <h5 class="card-title"><b>Elastic Logstash</b></h5>
+                                           </div>
+                                       </div>
+                                   </div>
+                               </div>
+                           </div>
+                           <a class="carousel-control-prev" href="#integrationCarousel" role="button" data-slide="prev">
+                               <span class="carousel-control-prev-icon" aria-hidden="true"></span>
+                               <span class="sr-only">Previous</span>
+                           </a>
+                           <a class="carousel-control-next" href="#integrationCarousel" role="button" data-slide="next">
+                               <span class="carousel-control-next-icon" aria-hidden="true"></span>
+                               <span class="sr-only">Next</span>
+                           </a>
+                       </div>
+                   </div>
+               </div>
+           </div>
+       </section>
+       <section id="secure" class="section-highlight section-highlight-primary">
+           <div class="container text-center">
+               <div class="row">
+                   <div class="col-lg-12 mx-auto">
+                       <i class="fas fa-lock fa-7x highlight-icon highlight-icon-primary"></i>
+                       <h2 class="section-highlight-text-primary">Secure by design.</h2>
+                       <p class="lead c-white">Not only are PLC4X drivers implemented with security in mind, also do our <b>passive-mode drivers</b> bring to you guaranteed side-effect-freeness without the need to pay for validated software.</p>
+                   </div>
+               </div>
+           </div>
+       </section>
+       <section id="performant" class="section-highlight section-highlight-secondary">
+           <div class="container text-center">
+               <div class="row">
+                   <div class="col-lg-12 mx-auto">
+                       <i class="fas fa-tachometer-alt fa-7x highlight-icon highlight-icon-secondary"></i>
+                       <h2 class="section-highlight-text-secondary">Get the performance you need.</h2>
+                       <p class="lead">Most approaches like OPC-UA currently don't deliver the performance needed for machine learning, deep learning and AI. PLC4X allows you to get the data volumes in the resolutons needed, without stressing out your industial hardware.</p>
+                   </div>
+               </div>
+           </div>
+       </section>
+       <section id="costs" class="section-highlight section-highlight-primary">
+           <div class="container text-center">
+               <div class="row">
+                   <div class="col-lg-12 mx-auto">
+                       <i class="fas fa-smile fa-7x highlight-icon highlight-icon-primary"></i>
+                       <h2 class="section-highlight-text-primary">No license-costs, no restrictive licenses.</h2>
+                       <p class="lead c-white">Being open-source, PLC4X is <b>free of charge</b>. Start experimenting
+                       without worrying about license costs or shady license agreements. The Apache 2.0 is one of the worlds <b>most trusted and adopted</b> open-source licenses out there.</p>
+                   </div>
+               </div>
+           </div>
+       </section>
+       <section id="with-support" class="section-highlight section-highlight-secondary">
+           <div class="container text-center">
+               <div class="row">
+                   <div class="col-lg-12 mx-auto">
+                       <i class="fas fa-info-circle fa-7x highlight-icon highlight-icon-secondary"></i>
+                       <h2 class="section-highlight-text-secondary">Get the commercial support you need.</h2>
+                       <p class="lead">Just because you can download and use PLC4X for free doesn't mean that your're left on your own. Some of our community member's comapnies can also provide your with the <b>commercial support</b> you need.</p>
+                   </div>
+               </div>
+           </div>
+       </section>
 ++++
diff --git a/src/site/resources/images/background-index-3.png b/src/site/resources/images/background-index-3.png
new file mode 100644
index 0000000..501f01b
Binary files /dev/null and b/src/site/resources/images/background-index-3.png differ